From 61174aaf0d58210b62f799d447b48c89e92c456d Mon Sep 17 00:00:00 2001
From: Joshua Ashton <joshua@froggi.es>
Date: Thu, 5 Mar 2020 06:19:51 +0000
Subject: [PATCH] winevulkan: Eliminate shared conversion structs

We don't need these any more since we stopped intercepting vkCmdPipelineBarrier for fshack.
---
 dlls/winevulkan/make_vulkan | 58 ++++++++++---------------------------
 1 file changed, 15 insertions(+), 43 deletions(-)

diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan
index b58ca9301cc..25bc7369074 100755
--- a/dlls/winevulkan/make_vulkan
+++ b/dlls/winevulkan/make_vulkan
@@ -219,8 +219,6 @@ STRUCT_CHAIN_CONVERSIONS = [
     "VkInstanceCreateInfo",
 ]
 
-shared_conversion_structs = ["VkBufferMemoryBarrier", "VkImageMemoryBarrier"]
-
 class Direction(Enum):
     """ Parameter direction: input, output, input_output. """
     INPUT = 1
@@ -1080,14 +1078,14 @@ class VkMember(object):
         struct = self.type_info["data"]
         direction = Direction.OUTPUT if struct.returnedonly else Direction.INPUT
         if self.is_dynamic_array():
-            conversions.append(ConversionFunction(False, True, struct.name in shared_conversion_structs, direction, struct))
+            conversions.append(ConversionFunction(False, True, direction, struct))
         elif self.is_static_array():
-            conversions.append(ConversionFunction(True, False, struct.name in shared_conversion_structs, direction, struct))
+            conversions.append(ConversionFunction(True, False, direction, struct))
         else:
-            conversions.append(ConversionFunction(False, False, struct.name in shared_conversion_structs, direction, struct))
+            conversions.append(ConversionFunction(False, False, direction, struct))
 
         if self.needs_free():
-            conversions.append(FreeFunction(self.is_dynamic_array(), struct.name in shared_conversion_structs, struct))
+            conversions.append(FreeFunction(self.is_dynamic_array(), struct))
 
         return conversions
 
@@ -1244,16 +1242,16 @@ class VkParam(object):
 
         # Input functions require win to host conversion.
         if self._direction in [Direction.INPUT, Direction.INPUT_OUTPUT]:
-            self.input_conv = ConversionFunction(False, self.is_dynamic_array(), self.struct.name in shared_conversion_structs, Direction.INPUT, self.struct)
+            self.input_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.INPUT, self.struct)
 
         # Output functions require host to win conversion.
         if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
-            self.output_conv = ConversionFunction(False, self.is_dynamic_array(), self.struct.name in shared_conversion_structs, Direction.OUTPUT, self.struct)
+            self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, self.struct)
 
         # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
         # allocation and thus some cleanup.
         if self.is_dynamic_array() or self.struct.needs_free():
-            self.free_func = FreeFunction(self.is_dynamic_array(), self.struct.name in shared_conversion_structs, self.struct)
+            self.free_func = FreeFunction(self.is_dynamic_array(), self.struct)
 
     def _set_direction(self):
         """ Internal helper function to set parameter direction (input/output/input_output). """
@@ -1729,10 +1727,9 @@ class VkStruct(Sequence):
 
 
 class ConversionFunction(object):
-    def __init__(self, array, dyn_array, shared, direction, struct):
+    def __init__(self, array, dyn_array, direction, struct):
         self.array = array
         self.direction = direction
-        self.shared = shared
         self.dyn_array = dyn_array
         self.struct = struct
         self.type = struct.name
@@ -1753,10 +1750,7 @@ class ConversionFunction(object):
             return_type = "{0}_host".format(self.type)
 
         # Generate function prototype.
-        if self.shared:
-            body = ""
-        else:
-            body = "static inline "
+        body = "static inline "
         body += "{0} *{1}(".format(return_type, self.name)
         body += ", ".join(p for p in params)
         body += ")\n{\n"
@@ -1788,10 +1782,7 @@ class ConversionFunction(object):
         else:
             params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
 
-        if self.shared:
-            body = ""
-        else:
-            body = "static inline "
+        body = "static inline "
         body += "void {0}(".format(self.name)
 
         # Generate parameter list
@@ -1825,10 +1816,7 @@ class ConversionFunction(object):
             params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
 
         # Generate function prototype.
-        if self.shared:
-            body = ""
-        else:
-            body = "static inline "
+        body = "static inline "
         body += "void {0}(".format(self.name)
         body += ", ".join(p for p in params)
         body += ")\n{\n"
@@ -1908,9 +1896,8 @@ class ConversionFunction(object):
 
 
 class FreeFunction(object):
-    def __init__(self, dyn_array, shared, struct):
+    def __init__(self, dyn_array, struct):
         self.dyn_array = dyn_array
-        self.shared = shared
         self.struct = struct
         self.type = struct.name
 
@@ -1926,10 +1913,7 @@ class FreeFunction(object):
         """ Helper function for cleaning up temporary buffers required for array conversions. """
 
         # Generate function prototype.
-        if self.shared:
-            body = ""
-        else:
-            body = "static inline "
+        body = "static inline "
         body += "void {0}({1}_host *in, uint32_t count)\n{{\n".format(self.name, self.type)
 
         # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
@@ -1963,10 +1947,7 @@ class FreeFunction(object):
             return ""
 
         # Generate function prototype.
-        if self.shared:
-            body = ""
-        else:
-            body = "static inline "
+        body = "static inline "
         body += "void {0}({1}_host *in)\n{{\n".format(self.name, self.type)
 
         for m in self.struct:
@@ -2137,14 +2118,9 @@ class VkGenerator(object):
         # Generate any conversion helper functions.
         f.write("#if defined(USE_STRUCT_CONVERSION)\n")
         for conv in self.conversions:
-            if not conv.shared:
-                f.write(conv.definition())
+            f.write(conv.definition())
         f.write("#endif /* USE_STRUCT_CONVERSION */\n\n")
 
-        for conv in self.conversions:
-            if conv.shared:
-                f.write(conv.definition())
-
         for conv in self.struct_chain_conversions:
             f.write(conv.definition())
 
@@ -2308,10 +2284,6 @@ class VkGenerator(object):
             f.write(func.prototype(postfix="DECLSPEC_HIDDEN") + ";\n")
         f.write("\n")
 
-        for conv in self.conversions:
-            if conv.shared:
-                f.write(conv.prototype())
-
         f.write("/* For use by vkDevice and children */\n")
         f.write("struct vulkan_device_funcs\n{\n")
         for vk_func in self.registry.device_funcs:
From 2e70e641784151d5a15db904ff6d1b25365de9b2 Mon Sep 17 00:00:00 2001
From: Joshua Ashton <joshua@froggi.es>
Date: Thu, 5 Mar 2020 06:26:22 +0000
Subject: [PATCH] winevulkan: Use alloca for struct conversions

This allocates these structs on the stack instead of the heap (which is expensive and takes time!)

These structures and arrays of structures are fairly small, and this is all super hot path code.
---
 dlls/winevulkan/make_vulkan      | 155 ++-----------------------------
 dlls/winevulkan/vulkan_private.h |  12 +++
 2 files changed, 22 insertions(+), 145 deletions(-)

diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan
index 25bc7369074..7f7967fde35 100755
--- a/dlls/winevulkan/make_vulkan
+++ b/dlls/winevulkan/make_vulkan
@@ -666,13 +666,6 @@ class VkFunction(object):
 
             body += p.copy(Direction.OUTPUT)
 
-        # Perform any required cleanups. Most of these are for array functions.
-        for p in self.params:
-            if not p.needs_free():
-                continue
-
-            body += p.free()
-
         # Finally return the result.
         if self.type != "void":
             body += "    return result;\n"
@@ -1084,9 +1077,6 @@ class VkMember(object):
         else:
             conversions.append(ConversionFunction(False, False, direction, struct))
 
-        if self.needs_free():
-            conversions.append(FreeFunction(self.is_dynamic_array(), struct))
-
         return conversions
 
     def is_const(self):
@@ -1152,17 +1142,6 @@ class VkMember(object):
         struct = self.type_info["data"]
         return struct.needs_conversion()
 
-    def needs_free(self):
-        if not self.needs_conversion():
-            return False
-
-        if self.is_dynamic_array():
-            return True
-
-        # TODO: some non-pointer structs and optional pointer structs may need freeing,
-        # though none of this type have been encountered yet.
-        return False
-
     def needs_struct_extensions_conversion(self):
         if not self.is_struct():
             return False
@@ -1248,11 +1227,6 @@ class VkParam(object):
         if self._direction in [Direction.INPUT_OUTPUT, Direction.OUTPUT]:
             self.output_conv = ConversionFunction(False, self.is_dynamic_array(), Direction.OUTPUT, self.struct)
 
-        # Dynamic arrays, but also some normal structs (e.g. VkCommandBufferBeginInfo) need memory
-        # allocation and thus some cleanup.
-        if self.is_dynamic_array() or self.struct.needs_free():
-            self.free_func = FreeFunction(self.is_dynamic_array(), self.struct)
-
     def _set_direction(self):
         """ Internal helper function to set parameter direction (input/output/input_output). """
 
@@ -1380,20 +1354,6 @@ class VkParam(object):
     def format_string(self):
         return self.format_str
 
-    def free(self):
-        if self.is_dynamic_array():
-            if self.struct.returnedonly:
-                # For returnedonly, counts is stored in a pointer.
-                return "    free_{0}_array({1}_host, *{2});\n".format(self.type, self.name, self.dyn_array_len)
-            else:
-                return "    free_{0}_array({1}_host, {2});\n".format(self.type, self.name, self.dyn_array_len)
-        else:
-            # We are operating on a single structure. Some structs (very rare) contain dynamic members,
-            # which would need freeing.
-            if self.struct.needs_free():
-                return "    free_{0}(&{1}_host);\n".format(self.type, self.name)
-        return ""
-
     def get_conversions(self):
         """ Get a list of conversions required for this parameter if any.
         Parameters which are structures may require conversion between win32
@@ -1430,8 +1390,6 @@ class VkParam(object):
             conversions.append(self.input_conv)
         if self.output_conv is not None:
             conversions.append(self.output_conv)
-        if self.free_func is not None:
-            conversions.append(self.free_func)
 
         return conversions
 
@@ -1479,9 +1437,6 @@ class VkParam(object):
 
         return False
 
-    def needs_free(self):
-        return self.free_func is not None
-
     def needs_input_conversion(self):
         return self.input_conv is not None
 
@@ -1694,17 +1649,6 @@ class VkStruct(Sequence):
                 return True
         return False
 
-    def needs_free(self):
-        """ Check if any struct member needs some memory freeing."""
-
-        for m in self.members:
-            if m.needs_free():
-                return True
-
-            continue
-
-        return False
-
     def needs_struct_extensions_conversion(self):
         """ Checks if structure extensions in pNext chain need conversion. """
         ret = False
@@ -1749,8 +1693,10 @@ class ConversionFunction(object):
             params = ["const {0} *in".format(self.type), "uint32_t count"]
             return_type = "{0}_host".format(self.type)
 
-        # Generate function prototype.
-        body = "static inline "
+        # We *must* forceinline otherwise our alloca will be
+        # garbage when this function returns.
+        # Regular inline won't cut it, alloca invalidates regular inlining.
+        body = "static WINEVULKAN_FORCEINLINE "
         body += "{0} *{1}(".format(return_type, self.name)
         body += ", ".join(p for p in params)
         body += ")\n{\n"
@@ -1759,7 +1705,7 @@ class ConversionFunction(object):
         body += "    unsigned int i;\n\n"
         body += "    if (!in) return NULL;\n\n"
 
-        body += "    out = heap_alloc(count * sizeof(*out));\n"
+        body += "    out = WINEVULKAN_ALLOCA(count * sizeof(*out));\n"
 
         body += "    for (i = 0; i < count; i++)\n"
         body += "    {\n"
@@ -1782,7 +1728,7 @@ class ConversionFunction(object):
         else:
             params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
 
-        body = "static inline "
+        body = "static WINEVULKAN_FORCEINLINE "
         body += "void {0}(".format(self.name)
 
         # Generate parameter list
@@ -1816,7 +1762,7 @@ class ConversionFunction(object):
             params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
 
         # Generate function prototype.
-        body = "static inline "
+        body = "static WINEVULKAN_FORCEINLINE "
         body += "void {0}(".format(self.name)
         body += ", ".join(p for p in params)
         body += ")\n{\n"
@@ -1868,7 +1814,7 @@ class ConversionFunction(object):
                 params = ["const {0} *in".format(self.type), "{0} *out_host".format(self.type), "uint32_t count"]
                 return_type = "{0}_host".format(self.type)
 
-            body = "void {0}(".format(self.name)
+            body = "static WINEVULKAN_FORCEINLINE void {0}(".format(self.name)
             body += ", ".join(p for p in params)
             body += ");\n"
         elif self.dyn_array:
@@ -1879,7 +1825,7 @@ class ConversionFunction(object):
                 params = ["const {0} *in".format(self.type), "uint32_t count"]
                 return_type = "{0}_host".format(self.type)
 
-            body = "{0} *{1}(".format(return_type, self.name)
+            body = "static WINEVULKAN_FORCEINLINE {0} *{1}(".format(return_type, self.name)
             body += ", ".join(p for p in params)
             body += ");\n"
         else:
@@ -1888,94 +1834,13 @@ class ConversionFunction(object):
             else:
                 params = ["const {0} *in".format(self.type), "{0}_host *out".format(self.type)]
 
-            body = "void {0}(".format(self.name)
+            body = "static WINEVULKAN_FORCEINLINE void {0}(".format(self.name)
             body += ", ".join(p for p in params)
             body += ");\n"
 
         return body
 
 
-class FreeFunction(object):
-    def __init__(self, dyn_array, struct):
-        self.dyn_array = dyn_array
-        self.struct = struct
-        self.type = struct.name
-
-        if dyn_array:
-            self.name = "free_{0}_array".format(self.type)
-        else:
-            self.name = "free_{0}".format(self.type)
-
-    def __eq__(self, other):
-        return self.name == other.name
-
-    def _generate_array_free_func(self):
-        """ Helper function for cleaning up temporary buffers required for array conversions. """
-
-        # Generate function prototype.
-        body = "static inline "
-        body += "void {0}({1}_host *in, uint32_t count)\n{{\n".format(self.name, self.type)
-
-        # E.g. VkGraphicsPipelineCreateInfo_host needs freeing for pStages.
-        if self.struct.needs_free():
-            body += "    unsigned int i;\n\n"
-            body += "    if (!in) return;\n\n"
-            body += "    for (i = 0; i < count; i++)\n"
-            body += "    {\n"
-
-            for m in self.struct:
-                if m.needs_conversion() and m.is_dynamic_array():
-                    if m.is_const():
-                        # Add a cast to ignore const on conversion structs we allocated ourselves.
-                        body += "        free_{0}_array(({0}_host *)in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
-                    else:
-                        body += "        free_{0}_array(in[i].{1}, in[i].{2});\n".format(m.type, m.name, m.dyn_array_len)
-                elif m.needs_conversion():
-                    LOGGER.error("Unhandled conversion for {0}".format(m.name))
-            body += "    }\n"
-        else:
-            body += "    if (!in) return;\n\n"
-
-        body += "    heap_free(in);\n"
-
-        body += "}\n\n"
-        return body
-
-    def _generate_free_func(self):
-        # E.g. VkCommandBufferBeginInfo.pInheritanceInfo needs freeing.
-        if not self.struct.needs_free():
-            return ""
-
-        # Generate function prototype.
-        body = "static inline "
-        body += "void {0}({1}_host *in)\n{{\n".format(self.name, self.type)
-
-        for m in self.struct:
-            if m.needs_conversion() and m.is_dynamic_array():
-                count = m.dyn_array_len if isinstance(m.dyn_array_len, int) else "in->{0}".format(m.dyn_array_len)
-                if m.is_const():
-                    # Add a cast to ignore const on conversion structs we allocated ourselves.
-                    body += "    free_{0}_array(({0}_host *)in->{1}, {2});\n".format(m.type, m.name, count)
-                else:
-                    body += "    free_{0}_array(in->{1}, {2});\n".format(m.type, m.name, count)
-
-        body += "}\n\n"
-        return body
-
-    def definition(self):
-        if self.dyn_array:
-            return self._generate_array_free_func()
-        else:
-            # Some structures need freeing too if they contain dynamic arrays.
-            # E.g. VkCommandBufferBeginInfo
-            return self._generate_free_func()
-
-    def prototype(self):
-        if self.dyn_array:
-            return "void {0}({1}_host *in, uint32_t count);\n".format(self.name, self.type)
-        return "void {0}({1}_host *in);\n".format(self.name, self.type)
-
-
 class StructChainConversionFunction(object):
     def __init__(self, direction, struct):
         self.direction = direction
diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h
index 00626eff1e3..ea2501ebc68 100644
--- a/dlls/winevulkan/vulkan_private.h
+++ b/dlls/winevulkan/vulkan_private.h
@@ -34,6 +34,18 @@
 
 #include "vulkan_thunks.h"
 
+#if defined(__GNUC__) || defined(__clang__)
+#include <alloca.h>
+#define WINEVULKAN_FORCEINLINE __attribute__((always_inline)) inline
+#define WINEVULKAN_ALLOCA(x)   alloca(x)
+#elif defined(_MSC_VER)
+#include <malloc.h>
+#define WINEVULKAN_FORCEINLINE __forceinline
+#define WINEVULKAN_ALLOCA(x)   _alloca(x)
+#else
+#error Unsupported platform for forceinline/alloca
+#endif
+
 /* Magic value defined by Vulkan ICD / Loader spec */
 #define VULKAN_ICD_MAGIC_VALUE 0x01CDC0DE
 
From 8e1498a5e028a3a5375c52c42e65652d21fa4d97 Mon Sep 17 00:00:00 2001
From: Joshua Ashton <joshua@froggi.es>
Date: Thu, 5 Mar 2020 06:26:48 +0000
Subject: [PATCH] winevulkan: Regenerate thunks

---
 dlls/winevulkan/vulkan_thunks.c | 512 +++++++++-----------------------
 dlls/winevulkan/vulkan_thunks.h |   4 -
 2 files changed, 133 insertions(+), 383 deletions(-)

diff --git a/dlls/winevulkan/vulkan_thunks.c b/dlls/winevulkan/vulkan_thunks.c
index ea9e8262d83..ae68cdeccc8 100644
--- a/dlls/winevulkan/vulkan_thunks.c
+++ b/dlls/winevulkan/vulkan_thunks.c
@@ -43,7 +43,7 @@
 WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
 
 #if defined(USE_STRUCT_CONVERSION)
-static inline void convert_VkAcquireNextImageInfoKHR_win_to_host(const VkAcquireNextImageInfoKHR *in, VkAcquireNextImageInfoKHR_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkAcquireNextImageInfoKHR_win_to_host(const VkAcquireNextImageInfoKHR *in, VkAcquireNextImageInfoKHR_host *out)
 {
     if (!in) return;
 
@@ -56,7 +56,7 @@ static inline void convert_VkAcquireNextImageInfoKHR_win_to_host(const VkAcquire
     out->deviceMask = in->deviceMask;
 }
 
-static inline void convert_VkDescriptorSetAllocateInfo_win_to_host(const VkDescriptorSetAllocateInfo *in, VkDescriptorSetAllocateInfo_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkDescriptorSetAllocateInfo_win_to_host(const VkDescriptorSetAllocateInfo *in, VkDescriptorSetAllocateInfo_host *out)
 {
     if (!in) return;
 
@@ -67,7 +67,7 @@ static inline void convert_VkDescriptorSetAllocateInfo_win_to_host(const VkDescr
     out->pSetLayouts = in->pSetLayouts;
 }
 
-static inline void convert_VkMemoryAllocateInfo_win_to_host(const VkMemoryAllocateInfo *in, VkMemoryAllocateInfo_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkMemoryAllocateInfo_win_to_host(const VkMemoryAllocateInfo *in, VkMemoryAllocateInfo_host *out)
 {
     if (!in) return;
 
@@ -77,14 +77,14 @@ static inline void convert_VkMemoryAllocateInfo_win_to_host(const VkMemoryAlloca
     out->memoryTypeIndex = in->memoryTypeIndex;
 }
 
-static inline VkCommandBufferInheritanceInfo_host *convert_VkCommandBufferInheritanceInfo_array_win_to_host(const VkCommandBufferInheritanceInfo *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkCommandBufferInheritanceInfo_host *convert_VkCommandBufferInheritanceInfo_array_win_to_host(const VkCommandBufferInheritanceInfo *in, uint32_t count)
 {
     VkCommandBufferInheritanceInfo_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].sType = in[i].sType;
@@ -100,14 +100,7 @@ static inline VkCommandBufferInheritanceInfo_host *convert_VkCommandBufferInheri
     return out;
 }
 
-static inline void free_VkCommandBufferInheritanceInfo_array(VkCommandBufferInheritanceInfo_host *in, uint32_t count)
-{
-    if (!in) return;
-
-    heap_free(in);
-}
-
-static inline void convert_VkCommandBufferBeginInfo_win_to_host(const VkCommandBufferBeginInfo *in, VkCommandBufferBeginInfo_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkCommandBufferBeginInfo_win_to_host(const VkCommandBufferBeginInfo *in, VkCommandBufferBeginInfo_host *out)
 {
     if (!in) return;
 
@@ -117,19 +110,14 @@ static inline void convert_VkCommandBufferBeginInfo_win_to_host(const VkCommandB
     out->pInheritanceInfo = convert_VkCommandBufferInheritanceInfo_array_win_to_host(in->pInheritanceInfo, 1);
 }
 
-static inline void free_VkCommandBufferBeginInfo(VkCommandBufferBeginInfo_host *in)
-{
-    free_VkCommandBufferInheritanceInfo_array((VkCommandBufferInheritanceInfo_host *)in->pInheritanceInfo, 1);
-}
-
-static inline VkBindAccelerationStructureMemoryInfoKHR_host *convert_VkBindAccelerationStructureMemoryInfoKHR_array_win_to_host(const VkBindAccelerationStructureMemoryInfoKHR *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkBindAccelerationStructureMemoryInfoKHR_host *convert_VkBindAccelerationStructureMemoryInfoKHR_array_win_to_host(const VkBindAccelerationStructureMemoryInfoKHR *in, uint32_t count)
 {
     VkBindAccelerationStructureMemoryInfoKHR_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].sType = in[i].sType;
@@ -144,21 +132,14 @@ static inline VkBindAccelerationStructureMemoryInfoKHR_host *convert_VkBindAccele
     return out;
 }
 
-static inline void free_VkBindAccelerationStructureMemoryInfoKHR_array(VkBindAccelerationStructureMemoryInfoKHR_host *in, uint32_t count)
-{
-    if (!in) return;
-
-    heap_free(in);
-}
-
-static inline VkBindBufferMemoryInfo_host *convert_VkBindBufferMemoryInfo_array_win_to_host(const VkBindBufferMemoryInfo *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkBindBufferMemoryInfo_host *convert_VkBindBufferMemoryInfo_array_win_to_host(const VkBindBufferMemoryInfo *in, uint32_t count)
 {
     VkBindBufferMemoryInfo_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].sType = in[i].sType;
@@ -171,21 +152,14 @@ static inline VkBindBufferMemoryInfo_host *convert_VkBindBufferMemoryInfo_array_
     return out;
 }
 
-static inline void free_VkBindBufferMemoryInfo_array(VkBindBufferMemoryInfo_host *in, uint32_t count)
-{
-    if (!in) return;
-
-    heap_free(in);
-}
-
-static inline VkBindImageMemoryInfo_host *convert_VkBindImageMemoryInfo_array_win_to_host(const VkBindImageMemoryInfo *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkBindImageMemoryInfo_host *convert_VkBindImageMemoryInfo_array_win_to_host(const VkBindImageMemoryInfo *in, uint32_t count)
 {
     VkBindImageMemoryInfo_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].sType = in[i].sType;
@@ -198,14 +172,7 @@ static inline VkBindImageMemoryInfo_host *convert_VkBindImageMemoryInfo_array_wi
     return out;
 }
 
-static inline void free_VkBindImageMemoryInfo_array(VkBindImageMemoryInfo_host *in, uint32_t count)
-{
-    if (!in) return;
-
-    heap_free(in);
-}
-
-static inline void convert_VkConditionalRenderingBeginInfoEXT_win_to_host(const VkConditionalRenderingBeginInfoEXT *in, VkConditionalRenderingBeginInfoEXT_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkConditionalRenderingBeginInfoEXT_win_to_host(const VkConditionalRenderingBeginInfoEXT *in, VkConditionalRenderingBeginInfoEXT_host *out)
 {
     if (!in) return;
 
@@ -216,7 +183,7 @@ static inline void convert_VkConditionalRenderingBeginInfoEXT_win_to_host(const
     out->flags = in->flags;
 }
 
-static inline void convert_VkRenderPassBeginInfo_win_to_host(const VkRenderPassBeginInfo *in, VkRenderPassBeginInfo_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkRenderPassBeginInfo_win_to_host(const VkRenderPassBeginInfo *in, VkRenderPassBeginInfo_host *out)
 {
     if (!in) return;
 
@@ -229,7 +196,7 @@ static inline void convert_VkRenderPassBeginInfo_win_to_host(const VkRenderPassB
     out->pClearValues = in->pClearValues;
 }
 
-static inline void convert_VkGeometryTrianglesNV_win_to_host(const VkGeometryTrianglesNV *in, VkGeometryTrianglesNV_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkGeometryTrianglesNV_win_to_host(const VkGeometryTrianglesNV *in, VkGeometryTrianglesNV_host *out)
 {
     if (!in) return;
 
@@ -248,7 +215,7 @@ static inline void convert_VkGeometryTrianglesNV_win_to_host(const VkGeometryTri
     out->transformOffset = in->transformOffset;
 }
 
-static inline void convert_VkGeometryAABBNV_win_to_host(const VkGeometryAABBNV *in, VkGeometryAABBNV_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkGeometryAABBNV_win_to_host(const VkGeometryAABBNV *in, VkGeometryAABBNV_host *out)
 {
     if (!in) return;
 
@@ -260,7 +227,7 @@ static inline void convert_VkGeometryAABBNV_win_to_host(const VkGeometryAABBNV *
     out->offset = in->offset;
 }
 
-static inline void convert_VkGeometryDataNV_win_to_host(const VkGeometryDataNV *in, VkGeometryDataNV_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkGeometryDataNV_win_to_host(const VkGeometryDataNV *in, VkGeometryDataNV_host *out)
 {
     if (!in) return;
 
@@ -268,14 +235,14 @@ static inline void convert_VkGeometryDataNV_win_to_host(const VkGeometryDataNV *
     convert_VkGeometryAABBNV_win_to_host(&in->aabbs, &out->aabbs);
 }
 
-static inline VkGeometryNV_host *convert_VkGeometryNV_array_win_to_host(const VkGeometryNV *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkGeometryNV_host *convert_VkGeometryNV_array_win_to_host(const VkGeometryNV *in, uint32_t count)
 {
     VkGeometryNV_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].sType = in[i].sType;
@@ -288,14 +255,7 @@ static inline VkGeometryNV_host *convert_VkGeometryNV_array_win_to_host(const Vk
     return out;
 }
 
-static inline void free_VkGeometryNV_array(VkGeometryNV_host *in, uint32_t count)
-{
-    if (!in) return;
-
-    heap_free(in);
-}
-
-static inline void convert_VkAccelerationStructureInfoNV_win_to_host(const VkAccelerationStructureInfoNV *in, VkAccelerationStructureInfoNV_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkAccelerationStructureInfoNV_win_to_host(const VkAccelerationStructureInfoNV *in, VkAccelerationStructureInfoNV_host *out)
 {
     if (!in) return;
 
@@ -308,19 +268,14 @@ static inline void convert_VkAccelerationStructureInfoNV_win_to_host(const VkAcc
     out->pGeometries = convert_VkGeometryNV_array_win_to_host(in->pGeometries, in->geometryCount);
 }
 
-static inline void free_VkAccelerationStructureInfoNV(VkAccelerationStructureInfoNV_host *in)
-{
-    free_VkGeometryNV_array((VkGeometryNV_host *)in->pGeometries, in->geometryCount);
-}
-
-static inline VkBufferCopy_host *convert_VkBufferCopy_array_win_to_host(const VkBufferCopy *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkBufferCopy_host *convert_VkBufferCopy_array_win_to_host(const VkBufferCopy *in, uint32_t count)
 {
     VkBufferCopy_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].srcOffset = in[i].srcOffset;
@@ -331,21 +286,14 @@ static inline VkBufferCopy_host *convert_VkBufferCopy_array_win_to_host(const Vk
     return out;
 }
 
-static inline void free_VkBufferCopy_array(VkBufferCopy_host *in, uint32_t count)
-{
-    if (!in) return;
-
-    heap_free(in);
-}
-
-static inline VkBufferImageCopy_host *convert_VkBufferImageCopy_array_win_to_host(const VkBufferImageCopy *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkBufferImageCopy_host *convert_VkBufferImageCopy_array_win_to_host(const VkBufferImageCopy *in, uint32_t count)
 {
     VkBufferImageCopy_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].bufferOffset = in[i].bufferOffset;
@@ -299,11 +299,28 @@ static inline VkBufferImageCopy_host *convert_VkBufferImageCopy_array_win_to_hos
     return out;
 }
 
-static inline void free_VkBufferImageCopy_array(VkBufferImageCopy_host *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkBufferMemoryBarrier_host *convert_VkBufferMemoryBarrier_array_win_to_host(const VkBufferMemoryBarrier *in, uint32_t count)
 {
-    if (!in) return;
+    VkBufferMemoryBarrier_host *out;
+    unsigned int i;
+
+    if (!in) return NULL;
+
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
+    for (i = 0; i < count; i++)
+    {
+        out[i].sType = in[i].sType;
+        out[i].pNext = in[i].pNext;
+        out[i].srcAccessMask = in[i].srcAccessMask;
+        out[i].dstAccessMask = in[i].dstAccessMask;
+        out[i].srcQueueFamilyIndex = in[i].srcQueueFamilyIndex;
+        out[i].dstQueueFamilyIndex = in[i].dstQueueFamilyIndex;
+        out[i].buffer = in[i].buffer;
+        out[i].offset = in[i].offset;
+        out[i].size = in[i].size;
+    }
 
-    heap_free(in);
+    return out;
 }
 
 static inline VkIndirectCommandsStreamNV_host *convert_VkIndirectCommandsStreamNV_array_win_to_host(const VkIndirectCommandsStreamNV *in, uint32_t count)
@@ -359,39 +359,57 @@ static inline VkBufferImageCopy_host *convert_VkBufferImageCopy_array_win_to_hos
     free_VkIndirectCommandsStreamNV_array((VkIndirectCommandsStreamNV_host *)in->pStreams, in->streamCount);
 }
 
-static inline VkDescriptorImageInfo_host *convert_VkDescriptorImageInfo_array_win_to_host(const VkDescriptorImageInfo *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkImageMemoryBarrier_host *convert_VkImageMemoryBarrier_array_win_to_host(const VkImageMemoryBarrier *in, uint32_t count)
 {
-    VkDescriptorImageInfo_host *out;
+    VkImageMemoryBarrier_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
-        out[i].sampler = in[i].sampler;
-        out[i].imageView = in[i].imageView;
-        out[i].imageLayout = in[i].imageLayout;
+        out[i].sType = in[i].sType;
+        out[i].pNext = in[i].pNext;
+        out[i].srcAccessMask = in[i].srcAccessMask;
+        out[i].dstAccessMask = in[i].dstAccessMask;
+        out[i].oldLayout = in[i].oldLayout;
+        out[i].newLayout = in[i].newLayout;
+        out[i].srcQueueFamilyIndex = in[i].srcQueueFamilyIndex;
+        out[i].dstQueueFamilyIndex = in[i].dstQueueFamilyIndex;
+        out[i].image = in[i].image;
+        out[i].subresourceRange = in[i].subresourceRange;
     }
 
     return out;
 }
 
-static inline void free_VkDescriptorImageInfo_array(VkDescriptorImageInfo_host *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkDescriptorImageInfo_host *convert_VkDescriptorImageInfo_array_win_to_host(const VkDescriptorImageInfo *in, uint32_t count)
 {
-    if (!in) return;
+    VkDescriptorImageInfo_host *out;
+    unsigned int i;
 
-    heap_free(in);
+    if (!in) return NULL;
+
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
+    for (i = 0; i < count; i++)
+    {
+        out[i].sampler = in[i].sampler;
+        out[i].imageView = in[i].imageView;
+        out[i].imageLayout = in[i].imageLayout;
+    }
+
+    return out;
 }
 
-static inline VkDescriptorBufferInfo_host *convert_VkDescriptorBufferInfo_array_win_to_host(const VkDescriptorBufferInfo *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkDescriptorBufferInfo_host *convert_VkDescriptorBufferInfo_array_win_to_host(const VkDescriptorBufferInfo *in, uint32_t count)
 {
     VkDescriptorBufferInfo_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].buffer = in[i].buffer;
@@ -409,21 +392,14 @@ static inline VkDescriptorBufferInfo_host *convert_VkDescriptorBufferInfo_array_
     return out;
 }
 
-static inline void free_VkDescriptorBufferInfo_array(VkDescriptorBufferInfo_host *in, uint32_t count)
-{
-    if (!in) return;
-
-    heap_free(in);
-}
-
-static inline VkWriteDescriptorSet_host *convert_VkWriteDescriptorSet_array_win_to_host(const VkWriteDescriptorSet *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkWriteDescriptorSet_host *convert_VkWriteDescriptorSet_array_win_to_host(const VkWriteDescriptorSet *in, uint32_t count)
 {
     VkWriteDescriptorSet_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].sType = in[i].sType;
@@ -441,21 +417,7 @@ static inline VkWriteDescriptorSet_host *convert_VkWriteDescriptorSet_array_win_
     return out;
 }
 
-static inline void free_VkWriteDescriptorSet_array(VkWriteDescriptorSet_host *in, uint32_t count)
-{
-    unsigned int i;
-
-    if (!in) return;
-
-    for (i = 0; i < count; i++)
-    {
-        free_VkDescriptorImageInfo_array((VkDescriptorImageInfo_host *)in[i].pImageInfo, in[i].descriptorCount);
-        free_VkDescriptorBufferInfo_array((VkDescriptorBufferInfo_host *)in[i].pBufferInfo, in[i].descriptorCount);
-    }
-    heap_free(in);
-}
-
-static inline void convert_VkPerformanceMarkerInfoINTEL_win_to_host(const VkPerformanceMarkerInfoINTEL *in, VkPerformanceMarkerInfoINTEL_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkPerformanceMarkerInfoINTEL_win_to_host(const VkPerformanceMarkerInfoINTEL *in, VkPerformanceMarkerInfoINTEL_host *out)
 {
     if (!in) return;
 
@@ -464,7 +426,7 @@ static inline void convert_VkPerformanceMarkerInfoINTEL_win_to_host(const VkPerf
     out->marker = in->marker;
 }
 
-static inline void convert_VkPerformanceOverrideInfoINTEL_win_to_host(const VkPerformanceOverrideInfoINTEL *in, VkPerformanceOverrideInfoINTEL_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkPerformanceOverrideInfoINTEL_win_to_host(const VkPerformanceOverrideInfoINTEL *in, VkPerformanceOverrideInfoINTEL_host *out)
 {
     if (!in) return;
 
@@ -475,7 +437,7 @@ static inline void convert_VkPerformanceOverrideInfoINTEL_win_to_host(const VkPe
     out->parameter = in->parameter;
 }
 
-static inline void convert_VkAccelerationStructureCreateInfoNV_win_to_host(const VkAccelerationStructureCreateInfoNV *in, VkAccelerationStructureCreateInfoNV_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkAccelerationStructureCreateInfoNV_win_to_host(const VkAccelerationStructureCreateInfoNV *in, VkAccelerationStructureCreateInfoNV_host *out)
 {
     if (!in) return;
 
@@ -485,7 +447,7 @@ static inline void convert_VkAccelerationStructureCreateInfoNV_win_to_host(const
     convert_VkAccelerationStructureInfoNV_win_to_host(&in->info, &out->info);
 }
 
-static inline void convert_VkBufferCreateInfo_win_to_host(const VkBufferCreateInfo *in, VkBufferCreateInfo_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkBufferCreateInfo_win_to_host(const VkBufferCreateInfo *in, VkBufferCreateInfo_host *out)
 {
     if (!in) return;
 
@@ -499,7 +461,7 @@ static inline void convert_VkBufferCreateInfo_win_to_host(const VkBufferCreateIn
     out->pQueueFamilyIndices = in->pQueueFamilyIndices;
 }
 
-static inline void convert_VkBufferViewCreateInfo_win_to_host(const VkBufferViewCreateInfo *in, VkBufferViewCreateInfo_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkBufferViewCreateInfo_win_to_host(const VkBufferViewCreateInfo *in, VkBufferViewCreateInfo_host *out)
 {
     if (!in) return;
 
@@ -512,7 +474,7 @@ static inline void convert_VkBufferViewCreateInfo_win_to_host(const VkBufferView
     out->range = in->range;
 }
 
-static inline void convert_VkPipelineShaderStageCreateInfo_win_to_host(const VkPipelineShaderStageCreateInfo *in, VkPipelineShaderStageCreateInfo_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkPipelineShaderStageCreateInfo_win_to_host(const VkPipelineShaderStageCreateInfo *in, VkPipelineShaderStageCreateInfo_host *out)
 {
     if (!in) return;
 
@@ -525,14 +487,14 @@ static inline void convert_VkPipelineShaderStageCreateInfo_win_to_host(const VkP
     out->pSpecializationInfo = in->pSpecializationInfo;
 }
 
-static inline VkComputePipelineCreateInfo_host *convert_VkComputePipelineCreateInfo_array_win_to_host(const VkComputePipelineCreateInfo *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkComputePipelineCreateInfo_host *convert_VkComputePipelineCreateInfo_array_win_to_host(const VkComputePipelineCreateInfo *in, uint32_t count)
 {
     VkComputePipelineCreateInfo_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].sType = in[i].sType;
@@ -547,14 +509,7 @@ static inline VkComputePipelineCreateInfo_host *convert_VkComputePipelineCreateI
     return out;
 }
 
-static inline void free_VkComputePipelineCreateInfo_array(VkComputePipelineCreateInfo_host *in, uint32_t count)
-{
-    if (!in) return;
-
-    heap_free(in);
-}
-
-static inline void convert_VkDescriptorUpdateTemplateCreateInfo_win_to_host(const VkDescriptorUpdateTemplateCreateInfo *in, VkDescriptorUpdateTemplateCreateInfo_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkDescriptorUpdateTemplateCreateInfo_win_to_host(const VkDescriptorUpdateTemplateCreateInfo *in, VkDescriptorUpdateTemplateCreateInfo_host *out)
 {
     if (!in) return;
 
@@ -570,7 +525,7 @@ static inline void convert_VkDescriptorUpdateTemplateCreateInfo_win_to_host(cons
     out->set = in->set;
 }
 
-static inline void convert_VkFramebufferCreateInfo_win_to_host(const VkFramebufferCreateInfo *in, VkFramebufferCreateInfo_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkFramebufferCreateInfo_win_to_host(const VkFramebufferCreateInfo *in, VkFramebufferCreateInfo_host *out)
 {
     if (!in) return;
 
@@ -585,14 +540,14 @@ static inline void convert_VkFramebufferCreateInfo_win_to_host(const VkFramebuff
     out->layers = in->layers;
 }
 
-static inline VkPipelineShaderStageCreateInfo_host *convert_VkPipelineShaderStageCreateInfo_array_win_to_host(const VkPipelineShaderStageCreateInfo *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkPipelineShaderStageCreateInfo_host *convert_VkPipelineShaderStageCreateInfo_array_win_to_host(const VkPipelineShaderStageCreateInfo *in, uint32_t count)
 {
     VkPipelineShaderStageCreateInfo_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].sType = in[i].sType;
@@ -607,21 +562,14 @@ static inline VkPipelineShaderStageCreateInfo_host *convert_VkPipelineShaderStag
     return out;
 }
 
-static inline void free_VkPipelineShaderStageCreateInfo_array(VkPipelineShaderStageCreateInfo_host *in, uint32_t count)
-{
-    if (!in) return;
-
-    heap_free(in);
-}
-
-static inline VkGraphicsPipelineCreateInfo_host *convert_VkGraphicsPipelineCreateInfo_array_win_to_host(const VkGraphicsPipelineCreateInfo *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkGraphicsPipelineCreateInfo_host *convert_VkGraphicsPipelineCreateInfo_array_win_to_host(const VkGraphicsPipelineCreateInfo *in, uint32_t count)
 {
     VkGraphicsPipelineCreateInfo_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].sType = in[i].sType;
@@ -648,20 +596,7 @@ static inline VkGraphicsPipelineCreateInfo_host *convert_VkGraphicsPipelineCreat
     return out;
 }
 
-static inline void free_VkGraphicsPipelineCreateInfo_array(VkGraphicsPipelineCreateInfo_host *in, uint32_t count)
-{
-    unsigned int i;
-
-    if (!in) return;
-
-    for (i = 0; i < count; i++)
-    {
-        free_VkPipelineShaderStageCreateInfo_array((VkPipelineShaderStageCreateInfo_host *)in[i].pStages, in[i].stageCount);
-    }
-    heap_free(in);
-}
-
-static inline void convert_VkImageViewCreateInfo_win_to_host(const VkImageViewCreateInfo *in, VkImageViewCreateInfo_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkImageViewCreateInfo_win_to_host(const VkImageViewCreateInfo *in, VkImageViewCreateInfo_host *out)
 {
     if (!in) return;
 
@@ -675,14 +610,14 @@ static inline void convert_VkImageViewCreateInfo_win_to_host(const VkImageViewCr
     out->subresourceRange = in->subresourceRange;
 }
 
-static inline VkRayTracingPipelineCreateInfoNV_host *convert_VkRayTracingPipelineCreateInfoNV_array_win_to_host(const VkRayTracingPipelineCreateInfoNV *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkRayTracingPipelineCreateInfoNV_host *convert_VkRayTracingPipelineCreateInfoNV_array_win_to_host(const VkRayTracingPipelineCreateInfoNV *in, uint32_t count)
 {
     VkRayTracingPipelineCreateInfoNV_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].sType = in[i].sType;
@@ -701,27 +636,14 @@ static inline VkRayTracingPipelineCreateInfoNV_host *convert_VkRayTracingPipelin
     return out;
 }
 
-static inline void free_VkRayTracingPipelineCreateInfoNV_array(VkRayTracingPipelineCreateInfoNV_host *in, uint32_t count)
-{
-    unsigned int i;
-
-    if (!in) return;
-
-    for (i = 0; i < count; i++)
-    {
-        free_VkPipelineShaderStageCreateInfo_array((VkPipelineShaderStageCreateInfo_host *)in[i].pStages, in[i].stageCount);
-    }
-    heap_free(in);
-}
-
-static inline VkMappedMemoryRange_host *convert_VkMappedMemoryRange_array_win_to_host(const VkMappedMemoryRange *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkMappedMemoryRange_host *convert_VkMappedMemoryRange_array_win_to_host(const VkMappedMemoryRange *in, uint32_t count)
 {
     VkMappedMemoryRange_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].sType = in[i].sType;
@@ -734,14 +656,7 @@ static inline VkMappedMemoryRange_host *convert_VkMappedMemoryRange_array_win_to
     return out;
 }
 
-static inline void free_VkMappedMemoryRange_array(VkMappedMemoryRange_host *in, uint32_t count)
-{
-    if (!in) return;
-
-    heap_free(in);
-}
-
-static inline void convert_VkAccelerationStructureMemoryRequirementsInfoNV_win_to_host(const VkAccelerationStructureMemoryRequirementsInfoNV *in, VkAccelerationStructureMemoryRequirementsInfoNV_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkAccelerationStructureMemoryRequirementsInfoNV_win_to_host(const VkAccelerationStructureMemoryRequirementsInfoNV *in, VkAccelerationStructureMemoryRequirementsInfoNV_host *out)
 {
     if (!in) return;
 
@@ -751,7 +666,7 @@ static inline void convert_VkAccelerationStructureMemoryRequirementsInfoNV_win_t
     out->accelerationStructure = in->accelerationStructure;
 }
 
-static inline void convert_VkMemoryRequirements_host_to_win(const VkMemoryRequirements_host *in, VkMemoryRequirements *out)
+static WINEVULKAN_FORCEINLINE void convert_VkMemoryRequirements_host_to_win(const VkMemoryRequirements_host *in, VkMemoryRequirements *out)
 {
     if (!in) return;
 
@@ -760,7 +675,7 @@ static inline void convert_VkMemoryRequirements_host_to_win(const VkMemoryRequir
     out->memoryTypeBits = in->memoryTypeBits;
 }
 
-static inline void convert_VkMemoryRequirements2KHR_win_to_host(const VkMemoryRequirements2KHR *in, VkMemoryRequirements2KHR_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkMemoryRequirements2KHR_win_to_host(const VkMemoryRequirements2KHR *in, VkMemoryRequirements2KHR_host *out)
 {
     if (!in) return;
 
@@ -768,7 +683,7 @@ static inline void convert_VkMemoryRequirements2KHR_win_to_host(const VkMemoryRe
     out->sType = in->sType;
 }
 
-static inline void convert_VkMemoryRequirements2KHR_host_to_win(const VkMemoryRequirements2KHR_host *in, VkMemoryRequirements2KHR *out)
+static WINEVULKAN_FORCEINLINE void convert_VkMemoryRequirements2KHR_host_to_win(const VkMemoryRequirements2KHR_host *in, VkMemoryRequirements2KHR *out)
 {
     if (!in) return;
 
@@ -777,7 +692,7 @@ static inline void convert_VkMemoryRequirements2KHR_host_to_win(const VkMemoryRe
     convert_VkMemoryRequirements_host_to_win(&in->memoryRequirements, &out->memoryRequirements);
 }
 
-static inline void convert_VkBufferDeviceAddressInfo_win_to_host(const VkBufferDeviceAddressInfo *in, VkBufferDeviceAddressInfo_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkBufferDeviceAddressInfo_win_to_host(const VkBufferDeviceAddressInfo *in, VkBufferDeviceAddressInfo_host *out)
 {
     if (!in) return;
 
@@ -786,7 +701,7 @@ static inline void convert_VkBufferDeviceAddressInfoKHR_win_to_host(const VkBuff
     out->buffer = in->buffer;
 }
 
-static inline void convert_VkBufferMemoryRequirementsInfo2_win_to_host(const VkBufferMemoryRequirementsInfo2 *in, VkBufferMemoryRequirementsInfo2_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkBufferMemoryRequirementsInfo2_win_to_host(const VkBufferMemoryRequirementsInfo2 *in, VkBufferMemoryRequirementsInfo2_host *out)
 {
     if (!in) return;
 
@@ -795,7 +710,7 @@ static inline void convert_VkBufferMemoryRequirementsInfo2_win_to_host(const VkB
     out->buffer = in->buffer;
 }
 
-static inline void convert_VkMemoryRequirements2_win_to_host(const VkMemoryRequirements2 *in, VkMemoryRequirements2_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkMemoryRequirements2_win_to_host(const VkMemoryRequirements2 *in, VkMemoryRequirements2_host *out)
 {
     if (!in) return;
 
@@ -803,7 +718,7 @@ static inline void convert_VkMemoryRequirements2_win_to_host(const VkMemoryRequi
     out->sType = in->sType;
 }
 
-static inline void convert_VkMemoryRequirements2_host_to_win(const VkMemoryRequirements2_host *in, VkMemoryRequirements2 *out)
+static WINEVULKAN_FORCEINLINE void convert_VkMemoryRequirements2_host_to_win(const VkMemoryRequirements2_host *in, VkMemoryRequirements2 *out)
 {
     if (!in) return;
 
@@ -812,7 +727,7 @@ static inline void convert_VkMemoryRequirements2_host_to_win(const VkMemoryRequi
     convert_VkMemoryRequirements_host_to_win(&in->memoryRequirements, &out->memoryRequirements);
 }
 
-static inline void convert_VkImageMemoryRequirementsInfo2_win_to_host(const VkImageMemoryRequirementsInfo2 *in, VkImageMemoryRequirementsInfo2_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkImageMemoryRequirementsInfo2_win_to_host(const VkImageMemoryRequirementsInfo2 *in, VkImageMemoryRequirementsInfo2_host *out)
 {
     if (!in) return;
 
@@ -821,7 +736,7 @@ static inline void convert_VkImageMemoryRequirementsInfo2_win_to_host(const VkIm
     out->image = in->image;
 }
 
-static inline void convert_VkImageSparseMemoryRequirementsInfo2_win_to_host(const VkImageSparseMemoryRequirementsInfo2 *in, VkImageSparseMemoryRequirementsInfo2_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkImageSparseMemoryRequirementsInfo2_win_to_host(const VkImageSparseMemoryRequirementsInfo2 *in, VkImageSparseMemoryRequirementsInfo2_host *out)
 {
     if (!in) return;
 
@@ -830,7 +745,7 @@ static inline void convert_VkImageSparseMemoryRequirementsInfo2_win_to_host(cons
     out->image = in->image;
 }
 
-static inline void convert_VkSubresourceLayout_host_to_win(const VkSubresourceLayout_host *in, VkSubresourceLayout *out)
+static WINEVULKAN_FORCEINLINE void convert_VkSubresourceLayout_host_to_win(const VkSubresourceLayout_host *in, VkSubresourceLayout *out)
 {
     if (!in) return;
 
@@ -841,7 +756,7 @@ static inline void convert_VkSubresourceLayout_host_to_win(const VkSubresourceLa
     out->depthPitch = in->depthPitch;
 }
 
-static inline void convert_VkImageFormatProperties_host_to_win(const VkImageFormatProperties_host *in, VkImageFormatProperties *out)
+static WINEVULKAN_FORCEINLINE void convert_VkImageFormatProperties_host_to_win(const VkImageFormatProperties_host *in, VkImageFormatProperties *out)
 {
     if (!in) return;
 
@@ -852,7 +767,7 @@ static inline void convert_VkImageFormatProperties_host_to_win(const VkImageForm
     out->maxResourceSize = in->maxResourceSize;
 }
 
-static inline void convert_VkImageFormatProperties2_win_to_host(const VkImageFormatProperties2 *in, VkImageFormatProperties2_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkImageFormatProperties2_win_to_host(const VkImageFormatProperties2 *in, VkImageFormatProperties2_host *out)
 {
     if (!in) return;
 
@@ -860,7 +775,7 @@ static inline void convert_VkImageFormatProperties2_win_to_host(const VkImageFor
     out->sType = in->sType;
 }
 
-static inline void convert_VkImageFormatProperties2_host_to_win(const VkImageFormatProperties2_host *in, VkImageFormatProperties2 *out)
+static WINEVULKAN_FORCEINLINE void convert_VkImageFormatProperties2_host_to_win(const VkImageFormatProperties2_host *in, VkImageFormatProperties2 *out)
 {
     if (!in) return;
 
@@ -869,7 +784,7 @@ static inline void convert_VkImageFormatProperties2_host_to_win(const VkImageFor
     convert_VkImageFormatProperties_host_to_win(&in->imageFormatProperties, &out->imageFormatProperties);
 }
 
-static inline void convert_VkMemoryHeap_static_array_host_to_win(const VkMemoryHeap_host *in, VkMemoryHeap *out, uint32_t count)
+static WINEVULKAN_FORCEINLINE void convert_VkMemoryHeap_static_array_host_to_win(const VkMemoryHeap_host *in, VkMemoryHeap *out, uint32_t count)
 {
     unsigned int i;
 
@@ -882,7 +797,7 @@ static inline void convert_VkMemoryHeap_static_array_host_to_win(const VkMemoryH
     }
 }
 
-static inline void convert_VkPhysicalDeviceMemoryProperties_host_to_win(const VkPhysicalDeviceMemoryProperties_host *in, VkPhysicalDeviceMemoryProperties *out)
+static WINEVULKAN_FORCEINLINE void convert_VkPhysicalDeviceMemoryProperties_host_to_win(const VkPhysicalDeviceMemoryProperties_host *in, VkPhysicalDeviceMemoryProperties *out)
 {
     if (!in) return;
 
@@ -892,7 +807,7 @@ static inline void convert_VkPhysicalDeviceMemoryProperties_host_to_win(const Vk
     convert_VkMemoryHeap_static_array_host_to_win(in->memoryHeaps, out->memoryHeaps, VK_MAX_MEMORY_HEAPS);
 }
 
-static inline void convert_VkPhysicalDeviceMemoryProperties2_win_to_host(const VkPhysicalDeviceMemoryProperties2 *in, VkPhysicalDeviceMemoryProperties2_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkPhysicalDeviceMemoryProperties2_win_to_host(const VkPhysicalDeviceMemoryProperties2 *in, VkPhysicalDeviceMemoryProperties2_host *out)
 {
     if (!in) return;
 
@@ -900,7 +815,7 @@ static inline void convert_VkPhysicalDeviceMemoryProperties2_win_to_host(const V
     out->sType = in->sType;
 }
 
-static inline void convert_VkPhysicalDeviceMemoryProperties2_host_to_win(const VkPhysicalDeviceMemoryProperties2_host *in, VkPhysicalDeviceMemoryProperties2 *out)
+static WINEVULKAN_FORCEINLINE void convert_VkPhysicalDeviceMemoryProperties2_host_to_win(const VkPhysicalDeviceMemoryProperties2_host *in, VkPhysicalDeviceMemoryProperties2 *out)
 {
     if (!in) return;
 
@@ -909,7 +824,7 @@ static inline void convert_VkPhysicalDeviceMemoryProperties2_host_to_win(const V
     convert_VkPhysicalDeviceMemoryProperties_host_to_win(&in->memoryProperties, &out->memoryProperties);
 }
 
-static inline void convert_VkPhysicalDeviceLimits_host_to_win(const VkPhysicalDeviceLimits_host *in, VkPhysicalDeviceLimits *out)
+static WINEVULKAN_FORCEINLINE void convert_VkPhysicalDeviceLimits_host_to_win(const VkPhysicalDeviceLimits_host *in, VkPhysicalDeviceLimits *out)
 {
     if (!in) return;
 
@@ -1021,7 +936,7 @@ static inline void convert_VkPhysicalDeviceLimits_host_to_win(const VkPhysicalDe
     out->nonCoherentAtomSize = in->nonCoherentAtomSize;
 }
 
-static inline void convert_VkPhysicalDeviceProperties_host_to_win(const VkPhysicalDeviceProperties_host *in, VkPhysicalDeviceProperties *out)
+static WINEVULKAN_FORCEINLINE void convert_VkPhysicalDeviceProperties_host_to_win(const VkPhysicalDeviceProperties_host *in, VkPhysicalDeviceProperties *out)
 {
     if (!in) return;
 
@@ -1036,7 +951,7 @@ static inline void convert_VkPhysicalDeviceProperties_host_to_win(const VkPhysic
     out->sparseProperties = in->sparseProperties;
 }
 
-static inline void convert_VkPhysicalDeviceProperties2_win_to_host(const VkPhysicalDeviceProperties2 *in, VkPhysicalDeviceProperties2_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkPhysicalDeviceProperties2_win_to_host(const VkPhysicalDeviceProperties2 *in, VkPhysicalDeviceProperties2_host *out)
 {
     if (!in) return;
 
@@ -1044,7 +959,7 @@ static inline void convert_VkPhysicalDeviceProperties2_win_to_host(const VkPhysi
     out->sType = in->sType;
 }
 
-static inline void convert_VkPhysicalDeviceProperties2_host_to_win(const VkPhysicalDeviceProperties2_host *in, VkPhysicalDeviceProperties2 *out)
+static WINEVULKAN_FORCEINLINE void convert_VkPhysicalDeviceProperties2_host_to_win(const VkPhysicalDeviceProperties2_host *in, VkPhysicalDeviceProperties2 *out)
 {
     if (!in) return;
 
@@ -1053,7 +968,7 @@ static inline void convert_VkPhysicalDeviceProperties2_host_to_win(const VkPhysi
     convert_VkPhysicalDeviceProperties_host_to_win(&in->properties, &out->properties);
 }
 
-static inline void convert_VkPipelineExecutableInfoKHR_win_to_host(const VkPipelineExecutableInfoKHR *in, VkPipelineExecutableInfoKHR_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkPipelineExecutableInfoKHR_win_to_host(const VkPipelineExecutableInfoKHR *in, VkPipelineExecutableInfoKHR_host *out)
 {
     if (!in) return;
 
@@ -1063,7 +978,7 @@ static inline void convert_VkPipelineExecutableInfoKHR_win_to_host(const VkPipel
     out->executableIndex = in->executableIndex;
 }
 
-static inline void convert_VkPipelineInfoKHR_win_to_host(const VkPipelineInfoKHR *in, VkPipelineInfoKHR_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkPipelineInfoKHR_win_to_host(const VkPipelineInfoKHR *in, VkPipelineInfoKHR_host *out)
 {
     if (!in) return;
 
@@ -1072,14 +987,14 @@ static inline void convert_VkPipelineInfoKHR_win_to_host(const VkPipelineInfoKHR
     out->pipeline = in->pipeline;
 }
 
-static inline VkSparseMemoryBind_host *convert_VkSparseMemoryBind_array_win_to_host(const VkSparseMemoryBind *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkSparseMemoryBind_host *convert_VkSparseMemoryBind_array_win_to_host(const VkSparseMemoryBind *in, uint32_t count)
 {
     VkSparseMemoryBind_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].resourceOffset = in[i].resourceOffset;
@@ -1092,21 +1007,14 @@ static inline VkSparseMemoryBind_host *convert_VkSparseMemoryBind_array_win_to_h
     return out;
 }
 
-static inline void free_VkSparseMemoryBind_array(VkSparseMemoryBind_host *in, uint32_t count)
-{
-    if (!in) return;
-
-    heap_free(in);
-}
-
-static inline VkSparseBufferMemoryBindInfo_host *convert_VkSparseBufferMemoryBindInfo_array_win_to_host(const VkSparseBufferMemoryBindInfo *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkSparseBufferMemoryBindInfo_host *convert_VkSparseBufferMemoryBindInfo_array_win_to_host(const VkSparseBufferMemoryBindInfo *in, uint32_t count)
 {
     VkSparseBufferMemoryBindInfo_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].buffer = in[i].buffer;
@@ -1117,27 +1025,14 @@ static inline VkSparseBufferMemoryBindInfo_host *convert_VkSparseBufferMemoryBin
     return out;
 }
 
-static inline void free_VkSparseBufferMemoryBindInfo_array(VkSparseBufferMemoryBindInfo_host *in, uint32_t count)
-{
-    unsigned int i;
-
-    if (!in) return;
-
-    for (i = 0; i < count; i++)
-    {
-        free_VkSparseMemoryBind_array((VkSparseMemoryBind_host *)in[i].pBinds, in[i].bindCount);
-    }
-    heap_free(in);
-}
-
-static inline VkSparseImageOpaqueMemoryBindInfo_host *convert_VkSparseImageOpaqueMemoryBindInfo_array_win_to_host(const VkSparseImageOpaqueMemoryBindInfo *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkSparseImageOpaqueMemoryBindInfo_host *convert_VkSparseImageOpaqueMemoryBindInfo_array_win_to_host(const VkSparseImageOpaqueMemoryBindInfo *in, uint32_t count)
 {
     VkSparseImageOpaqueMemoryBindInfo_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].image = in[i].image;
@@ -1148,27 +1043,14 @@ static inline VkSparseImageOpaqueMemoryBindInfo_host *convert_VkSparseImageOpaqu
     return out;
 }
 
-static inline void free_VkSparseImageOpaqueMemoryBindInfo_array(VkSparseImageOpaqueMemoryBindInfo_host *in, uint32_t count)
-{
-    unsigned int i;
-
-    if (!in) return;
-
-    for (i = 0; i < count; i++)
-    {
-        free_VkSparseMemoryBind_array((VkSparseMemoryBind_host *)in[i].pBinds, in[i].bindCount);
-    }
-    heap_free(in);
-}
-
-static inline VkSparseImageMemoryBind_host *convert_VkSparseImageMemoryBind_array_win_to_host(const VkSparseImageMemoryBind *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkSparseImageMemoryBind_host *convert_VkSparseImageMemoryBind_array_win_to_host(const VkSparseImageMemoryBind *in, uint32_t count)
 {
     VkSparseImageMemoryBind_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].subresource = in[i].subresource;
@@ -1182,21 +1064,14 @@ static inline VkSparseImageMemoryBind_host *convert_VkSparseImageMemoryBind_arra
     return out;
 }
 
-static inline void free_VkSparseImageMemoryBind_array(VkSparseImageMemoryBind_host *in, uint32_t count)
-{
-    if (!in) return;
-
-    heap_free(in);
-}
-
-static inline VkSparseImageMemoryBindInfo_host *convert_VkSparseImageMemoryBindInfo_array_win_to_host(const VkSparseImageMemoryBindInfo *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkSparseImageMemoryBindInfo_host *convert_VkSparseImageMemoryBindInfo_array_win_to_host(const VkSparseImageMemoryBindInfo *in, uint32_t count)
 {
     VkSparseImageMemoryBindInfo_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].image = in[i].image;
@@ -1207,27 +1082,14 @@ static inline VkSparseImageMemoryBindInfo_host *convert_VkSparseImageMemoryBindI
     return out;
 }
 
-static inline void free_VkSparseImageMemoryBindInfo_array(VkSparseImageMemoryBindInfo_host *in, uint32_t count)
-{
-    unsigned int i;
-
-    if (!in) return;
-
-    for (i = 0; i < count; i++)
-    {
-        free_VkSparseImageMemoryBind_array((VkSparseImageMemoryBind_host *)in[i].pBinds, in[i].bindCount);
-    }
-    heap_free(in);
-}
-
-static inline VkBindSparseInfo_host *convert_VkBindSparseInfo_array_win_to_host(const VkBindSparseInfo *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkBindSparseInfo_host *convert_VkBindSparseInfo_array_win_to_host(const VkBindSparseInfo *in, uint32_t count)
 {
     VkBindSparseInfo_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].sType = in[i].sType;
@@ -1247,22 +1109,7 @@ static inline VkBindSparseInfo_host *convert_VkBindSparseInfo_array_win_to_host(
     return out;
 }
 
-static inline void free_VkBindSparseInfo_array(VkBindSparseInfo_host *in, uint32_t count)
-{
-    unsigned int i;
-
-    if (!in) return;
-
-    for (i = 0; i < count; i++)
-    {
-        free_VkSparseBufferMemoryBindInfo_array((VkSparseBufferMemoryBindInfo_host *)in[i].pBufferBinds, in[i].bufferBindCount);
-        free_VkSparseImageOpaqueMemoryBindInfo_array((VkSparseImageOpaqueMemoryBindInfo_host *)in[i].pImageOpaqueBinds, in[i].imageOpaqueBindCount);
-        free_VkSparseImageMemoryBindInfo_array((VkSparseImageMemoryBindInfo_host *)in[i].pImageBinds, in[i].imageBindCount);
-    }
-    heap_free(in);
-}
-
-static inline void convert_VkSemaphoreSignalInfo_win_to_host(const VkSemaphoreSignalInfo *in, VkSemaphoreSignalInfo_host *out)
+static WINEVULKAN_FORCEINLINE void convert_VkSemaphoreSignalInfo_win_to_host(const VkSemaphoreSignalInfo *in, VkSemaphoreSignalInfo_host *out)
 {
     if (!in) return;
 
@@ -1272,14 +1119,14 @@ static inline void convert_VkSemaphoreSignalInfoKHR_win_to_host(const VkSemaphor
     out->value = in->value;
 }
 
-static inline VkCopyDescriptorSet_host *convert_VkCopyDescriptorSet_array_win_to_host(const VkCopyDescriptorSet *in, uint32_t count)
+static WINEVULKAN_FORCEINLINE VkCopyDescriptorSet_host *convert_VkCopyDescriptorSet_array_win_to_host(const VkCopyDescriptorSet *in, uint32_t count)
 {
     VkCopyDescriptorSet_host *out;
     unsigned int i;
 
     if (!in) return NULL;
 
-    out = heap_alloc(count * sizeof(*out));
+    out = WINEVULKAN_ALLOCA(count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
         out[i].sType = in[i].sType;
@@ -1296,13 +1143,6 @@ static inline VkCopyDescriptorSet_host *convert_VkCopyDescriptorSet_array_win_to
     return out;
 }
 
-static inline void free_VkCopyDescriptorSet_array(VkCopyDescriptorSet_host *in, uint32_t count)
-{
-    if (!in) return;
-
-    heap_free(in);
-}
-
 #endif /* USE_STRUCT_CONVERSION */
 
 VkResult convert_VkDeviceCreateInfo_struct_chain(const void *pNext, VkDeviceCreateInfo *out_struct)
@@ -2300,69 +2140,6 @@ void free_VkInstanceCreateInfo_struct_chain(VkInstanceCreateInfo *s)
     s->pNext = NULL;
 }
 
-VkBufferMemoryBarrier_host *convert_VkBufferMemoryBarrier_array_win_to_host(const VkBufferMemoryBarrier *in, uint32_t count)
-{
-    VkBufferMemoryBarrier_host *out;
-    unsigned int i;
-
-    if (!in) return NULL;
-
-    out = heap_alloc(count * sizeof(*out));
-    for (i = 0; i < count; i++)
-    {
-        out[i].sType = in[i].sType;
-        out[i].pNext = in[i].pNext;
-        out[i].srcAccessMask = in[i].srcAccessMask;
-        out[i].dstAccessMask = in[i].dstAccessMask;
-        out[i].srcQueueFamilyIndex = in[i].srcQueueFamilyIndex;
-        out[i].dstQueueFamilyIndex = in[i].dstQueueFamilyIndex;
-        out[i].buffer = in[i].buffer;
-        out[i].offset = in[i].offset;
-        out[i].size = in[i].size;
-    }
-
-    return out;
-}
-
-void free_VkBufferMemoryBarrier_array(VkBufferMemoryBarrier_host *in, uint32_t count)
-{
-    if (!in) return;
-
-    heap_free(in);
-}
-
-VkImageMemoryBarrier_host *convert_VkImageMemoryBarrier_array_win_to_host(const VkImageMemoryBarrier *in, uint32_t count)
-{
-    VkImageMemoryBarrier_host *out;
-    unsigned int i;
-
-    if (!in) return NULL;
-
-    out = heap_alloc(count * sizeof(*out));
-    for (i = 0; i < count; i++)
-    {
-        out[i].sType = in[i].sType;
-        out[i].pNext = in[i].pNext;
-        out[i].srcAccessMask = in[i].srcAccessMask;
-        out[i].dstAccessMask = in[i].dstAccessMask;
-        out[i].oldLayout = in[i].oldLayout;
-        out[i].newLayout = in[i].newLayout;
-        out[i].srcQueueFamilyIndex = in[i].srcQueueFamilyIndex;
-        out[i].dstQueueFamilyIndex = in[i].dstQueueFamilyIndex;
-        out[i].image = in[i].image;
-        out[i].subresourceRange = in[i].subresourceRange;
-    }
-
-    return out;
-}
-
-void free_VkImageMemoryBarrier_array(VkImageMemoryBarrier_host *in, uint32_t count)
-{
-    if (!in) return;
-
-    heap_free(in);
-}
-
 VkResult WINAPI wine_vkAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR *pAcquireInfo, uint32_t *pImageIndex)
 {
 #if defined(USE_STRUCT_CONVERSION)
@@ -2430,7 +2207,6 @@ VkResult WINAPI wine_vkBeginCommandBuffer(VkCommandBuffer commandBuffer, const V
     convert_VkCommandBufferBeginInfo_win_to_host(pBeginInfo, &pBeginInfo_host);
     result = commandBuffer->device->funcs.p_vkBeginCommandBuffer(commandBuffer->command_buffer, &pBeginInfo_host);
 
-    free_VkCommandBufferBeginInfo(&pBeginInfo_host);
     return result;
 #else
     TRACE("%p, %p\n", commandBuffer, pBeginInfo);
@@ -2448,7 +2224,6 @@ static VkResult WINAPI wine_vkBindAccelerationStructureMemoryNV(VkDevice device,
     pBindInfos_host = convert_VkBindAccelerationStructureMemoryInfoNV_array_win_to_host(pBindInfos, bindInfoCount);
     result = device->funcs.p_vkBindAccelerationStructureMemoryNV(device->device, bindInfoCount, pBindInfos_host);
 
-    free_VkBindAccelerationStructureMemoryInfoKHR_array(pBindInfos_host, bindInfoCount);
     return result;
 #else
     TRACE("%p, %u, %p\n", device, bindInfoCount, pBindInfos);
@@ -2472,7 +2247,6 @@ VkResult WINAPI wine_vkBindBufferMemory2(VkDevice device, uint32_t bindInfoCount
     pBindInfos_host = convert_VkBindBufferMemoryInfo_array_win_to_host(pBindInfos, bindInfoCount);
     result = device->funcs.p_vkBindBufferMemory2(device->device, bindInfoCount, pBindInfos_host);
 
-    free_VkBindBufferMemoryInfo_array(pBindInfos_host, bindInfoCount);
     return result;
 #else
     TRACE("%p, %u, %p\n", device, bindInfoCount, pBindInfos);
@@ -2490,7 +2264,6 @@ static VkResult WINAPI wine_vkBindBufferMemory2KHR(VkDevice device, uint32_t bin
     pBindInfos_host = convert_VkBindBufferMemoryInfo_array_win_to_host(pBindInfos, bindInfoCount);
     result = device->funcs.p_vkBindBufferMemory2KHR(device->device, bindInfoCount, pBindInfos_host);
 
-    free_VkBindBufferMemoryInfo_array(pBindInfos_host, bindInfoCount);
     return result;
 #else
     TRACE("%p, %u, %p\n", device, bindInfoCount, pBindInfos);
@@ -2514,7 +2287,6 @@ VkResult WINAPI wine_vkBindImageMemory2(VkDevice device, uint32_t bindInfoCount,
     pBindInfos_host = convert_VkBindImageMemoryInfo_array_win_to_host(pBindInfos, bindInfoCount);
     result = device->funcs.p_vkBindImageMemory2(device->device, bindInfoCount, pBindInfos_host);
 
-    free_VkBindImageMemoryInfo_array(pBindInfos_host, bindInfoCount);
     return result;
 #else
     TRACE("%p, %u, %p\n", device, bindInfoCount, pBindInfos);
@@ -2532,7 +2304,6 @@ static VkResult WINAPI wine_vkBindImageMemory2KHR(VkDevice device, uint32_t bind
     pBindInfos_host = convert_VkBindImageMemoryInfo_array_win_to_host(pBindInfos, bindInfoCount);
     result = device->funcs.p_vkBindImageMemory2KHR(device->device, bindInfoCount, pBindInfos_host);
 
-    free_VkBindImageMemoryInfo_array(pBindInfos_host, bindInfoCount);
     return result;
 #else
     TRACE("%p, %u, %p\n", device, bindInfoCount, pBindInfos);
@@ -2654,7 +2425,6 @@ static void WINAPI wine_vkCmdBuildAccelerationStructureNV(VkCommandBuffer comman
     convert_VkAccelerationStructureInfoNV_win_to_host(pInfo, &pInfo_host);
     commandBuffer->device->funcs.p_vkCmdBuildAccelerationStructureNV(commandBuffer->command_buffer, &pInfo_host, instanceData, instanceOffset, update, dst, src, scratch, scratchOffset);
 
-    free_VkAccelerationStructureInfoNV(&pInfo_host);
 #else
     TRACE("%p, %p, 0x%s, 0x%s, %u, 0x%s, 0x%s, 0x%s, 0x%s\n", commandBuffer, pInfo, wine_dbgstr_longlong(instanceData), wine_dbgstr_longlong(instanceOffset), update, wine_dbgstr_longlong(dst), wine_dbgstr_longlong(src), wine_dbgstr_longlong(scratch), wine_dbgstr_longlong(scratchOffset));
     commandBuffer->device->funcs.p_vkCmdBuildAccelerationStructureNV(commandBuffer->command_buffer, pInfo, instanceData, instanceOffset, update, dst, src, scratch, scratchOffset);
@@ -2694,7 +2464,6 @@ void WINAPI wine_vkCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuff
     pRegions_host = convert_VkBufferCopy_array_win_to_host(pRegions, regionCount);
     commandBuffer->device->funcs.p_vkCmdCopyBuffer(commandBuffer->command_buffer, srcBuffer, dstBuffer, regionCount, pRegions_host);
 
-    free_VkBufferCopy_array(pRegions_host, regionCount);
 #else
     TRACE("%p, 0x%s, 0x%s, %u, %p\n", commandBuffer, wine_dbgstr_longlong(srcBuffer), wine_dbgstr_longlong(dstBuffer), regionCount, pRegions);
     commandBuffer->device->funcs.p_vkCmdCopyBuffer(commandBuffer->command_buffer, srcBuffer, dstBuffer, regionCount, pRegions);
@@ -2710,7 +2479,6 @@ void WINAPI wine_vkCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer
     pRegions_host = convert_VkBufferImageCopy_array_win_to_host(pRegions, regionCount);
     commandBuffer->device->funcs.p_vkCmdCopyBufferToImage(commandBuffer->command_buffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions_host);
 
-    free_VkBufferImageCopy_array(pRegions_host, regionCount);
 #else
     TRACE("%p, 0x%s, 0x%s, %#x, %u, %p\n", commandBuffer, wine_dbgstr_longlong(srcBuffer), wine_dbgstr_longlong(dstImage), dstImageLayout, regionCount, pRegions);
     commandBuffer->device->funcs.p_vkCmdCopyBufferToImage(commandBuffer->command_buffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions);
@@ -2732,7 +2500,6 @@ void WINAPI wine_vkCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage s
     pRegions_host = convert_VkBufferImageCopy_array_win_to_host(pRegions, regionCount);
     commandBuffer->device->funcs.p_vkCmdCopyImageToBuffer(commandBuffer->command_buffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions_host);
 
-    free_VkBufferImageCopy_array(pRegions_host, regionCount);
 #else
     TRACE("%p, 0x%s, %#x, 0x%s, %u, %p\n", commandBuffer, wine_dbgstr_longlong(srcImage), srcImageLayout, wine_dbgstr_longlong(dstBuffer), regionCount, pRegions);
     commandBuffer->device->funcs.p_vkCmdCopyImageToBuffer(commandBuffer->command_buffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
@@ -2906,8 +2673,6 @@ void WINAPI wine_vkCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineS
     pImageMemoryBarriers_host = convert_VkImageMemoryBarrier_array_win_to_host(pImageMemoryBarriers, imageMemoryBarrierCount);
     commandBuffer->device->funcs.p_vkCmdPipelineBarrier(commandBuffer->command_buffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers_host, imageMemoryBarrierCount, pImageMemoryBarriers_host);
 
-    free_VkBufferMemoryBarrier_array(pBufferMemoryBarriers_host, bufferMemoryBarrierCount);
-    free_VkImageMemoryBarrier_array(pImageMemoryBarriers_host, imageMemoryBarrierCount);
 #else
     TRACE("%p, %#x, %#x, %#x, %u, %p, %u, %p, %u, %p\n", commandBuffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
     commandBuffer->device->funcs.p_vkCmdPipelineBarrier(commandBuffer->command_buffer, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
@@ -2929,7 +2694,6 @@ static void WINAPI wine_vkCmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer,
     pDescriptorWrites_host = convert_VkWriteDescriptorSet_array_win_to_host(pDescriptorWrites, descriptorWriteCount);
     commandBuffer->device->funcs.p_vkCmdPushDescriptorSetKHR(commandBuffer->command_buffer, pipelineBindPoint, layout, set, descriptorWriteCount, pDescriptorWrites_host);
 
-    free_VkWriteDescriptorSet_array(pDescriptorWrites_host, descriptorWriteCount);
 #else
     TRACE("%p, %#x, 0x%s, %u, %u, %p\n", commandBuffer, pipelineBindPoint, wine_dbgstr_longlong(layout), set, descriptorWriteCount, pDescriptorWrites);
     commandBuffer->device->funcs.p_vkCmdPushDescriptorSetKHR(commandBuffer->command_buffer, pipelineBindPoint, layout, set, descriptorWriteCount, pDescriptorWrites);
@@ -3143,8 +2907,6 @@ void WINAPI wine_vkCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCo
     pImageMemoryBarriers_host = convert_VkImageMemoryBarrier_array_win_to_host(pImageMemoryBarriers, imageMemoryBarrierCount);
     commandBuffer->device->funcs.p_vkCmdWaitEvents(commandBuffer->command_buffer, eventCount, pEvents, srcStageMask, dstStageMask, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers_host, imageMemoryBarrierCount, pImageMemoryBarriers_host);
 
-    free_VkBufferMemoryBarrier_array(pBufferMemoryBarriers_host, bufferMemoryBarrierCount);
-    free_VkImageMemoryBarrier_array(pImageMemoryBarriers_host, imageMemoryBarrierCount);
 #else
     TRACE("%p, %u, %p, %#x, %#x, %u, %p, %u, %p, %u, %p\n", commandBuffer, eventCount, pEvents, srcStageMask, dstStageMask, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
     commandBuffer->device->funcs.p_vkCmdWaitEvents(commandBuffer->command_buffer, eventCount, pEvents, srcStageMask, dstStageMask, memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
@@ -3236,7 +2998,6 @@ VkResult WINAPI wine_vkCreateComputePipelines(VkDevice device, VkPipelineCache p
     pCreateInfos_host = convert_VkComputePipelineCreateInfo_array_win_to_host(pCreateInfos, createInfoCount);
     result = device->funcs.p_vkCreateComputePipelines(device->device, pipelineCache, createInfoCount, pCreateInfos_host, NULL, pPipelines);
 
-    free_VkComputePipelineCreateInfo_array(pCreateInfos_host, createInfoCount);
     return result;
 #else
     TRACE("%p, 0x%s, %u, %p, %p, %p\n", device, wine_dbgstr_longlong(pipelineCache), createInfoCount, pCreateInfos, pAllocator, pPipelines);
@@ -3329,7 +3090,6 @@ VkResult WINAPI wine_vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache
     pCreateInfos_host = convert_VkGraphicsPipelineCreateInfo_array_win_to_host(pCreateInfos, createInfoCount);
     result = device->funcs.p_vkCreateGraphicsPipelines(device->device, pipelineCache, createInfoCount, pCreateInfos_host, NULL, pPipelines);
 
-    free_VkGraphicsPipelineCreateInfo_array(pCreateInfos_host, createInfoCount);
     return result;
 #else
     TRACE("%p, 0x%s, %u, %p, %p, %p\n", device, wine_dbgstr_longlong(pipelineCache), createInfoCount, pCreateInfos, pAllocator, pPipelines);
@@ -3394,7 +3154,6 @@ static VkResult WINAPI wine_vkCreateRayTracingPipelinesNV(VkDevice device, VkPip
     pCreateInfos_host = convert_VkRayTracingPipelineCreateInfoNV_array_win_to_host(pCreateInfos, createInfoCount);
     result = device->funcs.p_vkCreateRayTracingPipelinesNV(device->device, pipelineCache, createInfoCount, pCreateInfos_host, NULL, pPipelines);
 
-    free_VkRayTracingPipelineCreateInfoNV_array(pCreateInfos_host, createInfoCount);
     return result;
 #else
     TRACE("%p, 0x%s, %u, %p, %p, %p\n", device, wine_dbgstr_longlong(pipelineCache), createInfoCount, pCreateInfos, pAllocator, pPipelines);
@@ -3628,7 +3387,6 @@ VkResult WINAPI wine_vkFlushMappedMemoryRanges(VkDevice device, uint32_t memoryR
     pMemoryRanges_host = convert_VkMappedMemoryRange_array_win_to_host(pMemoryRanges, memoryRangeCount);
     result = device->funcs.p_vkFlushMappedMemoryRanges(device->device, memoryRangeCount, pMemoryRanges_host);
 
-    free_VkMappedMemoryRange_array(pMemoryRanges_host, memoryRangeCount);
     return result;
 #else
     TRACE("%p, %u, %p\n", device, memoryRangeCount, pMemoryRanges);
@@ -4289,7 +4047,6 @@ VkResult WINAPI wine_vkInvalidateMappedMemoryRanges(VkDevice device, uint32_t me
     pMemoryRanges_host = convert_VkMappedMemoryRange_array_win_to_host(pMemoryRanges, memoryRangeCount);
     result = device->funcs.p_vkInvalidateMappedMemoryRanges(device->device, memoryRangeCount, pMemoryRanges_host);
 
-    free_VkMappedMemoryRange_array(pMemoryRanges_host, memoryRangeCount);
     return result;
 #else
     TRACE("%p, %u, %p\n", device, memoryRangeCount, pMemoryRanges);
@@ -4325,7 +4082,6 @@ VkResult WINAPI wine_vkQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, co
     pBindInfo_host = convert_VkBindSparseInfo_array_win_to_host(pBindInfo, bindInfoCount);
     result = queue->device->funcs.p_vkQueueBindSparse(queue->queue, bindInfoCount, pBindInfo_host, fence);
 
-    free_VkBindSparseInfo_array(pBindInfo_host, bindInfoCount);
     return result;
 #else
     TRACE("%p, %u, %p, 0x%s\n", queue, bindInfoCount, pBindInfo, wine_dbgstr_longlong(fence));
@@ -4457,8 +4213,6 @@ void WINAPI wine_vkUpdateDescriptorSets(VkDevice device, uint32_t descriptorWrit
     pDescriptorCopies_host = convert_VkCopyDescriptorSet_array_win_to_host(pDescriptorCopies, descriptorCopyCount);
     device->funcs.p_vkUpdateDescriptorSets(device->device, descriptorWriteCount, pDescriptorWrites_host, descriptorCopyCount, pDescriptorCopies_host);
 
-    free_VkWriteDescriptorSet_array(pDescriptorWrites_host, descriptorWriteCount);
-    free_VkCopyDescriptorSet_array(pDescriptorCopies_host, descriptorCopyCount);
 #else
     TRACE("%p, %u, %p, %u, %p\n", device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount, pDescriptorCopies);
     device->funcs.p_vkUpdateDescriptorSets(device->device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount, pDescriptorCopies);
diff --git a/dlls/winevulkan/vulkan_thunks.h b/dlls/winevulkan/vulkan_thunks.h
index 82d0c3a0a5e..57d64cd1215 100644
--- a/dlls/winevulkan/vulkan_thunks.h
+++ b/dlls/winevulkan/vulkan_thunks.h
@@ -816,10 +816,6 @@ void free_VkDeviceCreateInfo_struct_chain(VkDeviceCreateInfo *s) DECLSPEC_HIDDEN
 VkResult convert_VkInstanceCreateInfo_struct_chain(const void *pNext, VkInstanceCreateInfo *out_struct) DECLSPEC_HIDDEN;
 void free_VkInstanceCreateInfo_struct_chain(VkInstanceCreateInfo *s) DECLSPEC_HIDDEN;
 
-VkBufferMemoryBarrier_host *convert_VkBufferMemoryBarrier_array_win_to_host(const VkBufferMemoryBarrier *in, uint32_t count);
-void free_VkBufferMemoryBarrier_array(VkBufferMemoryBarrier_host *in, uint32_t count);
-VkImageMemoryBarrier_host *convert_VkImageMemoryBarrier_array_win_to_host(const VkImageMemoryBarrier *in, uint32_t count);
-void free_VkImageMemoryBarrier_array(VkImageMemoryBarrier_host *in, uint32_t count);
 /* For use by vkDevice and children */
 struct vulkan_device_funcs
 {
 
From d8388b630c69d58ffd8a8b7ac7f43cd343e77f8b Mon Sep 17 00:00:00 2001
From: Georg Lehmann <dadschoorse@gmail.com>
Date: Wed, 4 Mar 2020 21:49:16 +0100
Subject: [PATCH] winevulkan: use swapchain format for fshack image + view

---
 dlls/winevulkan/vulkan.c         | 93 ++++++++++++++------------------
 dlls/winevulkan/vulkan_private.h |  1 +
 2 files changed, 42 insertions(+), 52 deletions(-)

diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
index b6ad2dc4b3d..920f203d830 100644
--- a/dlls/winevulkan/vulkan.c
+++ b/dlls/winevulkan/vulkan.c
@@ -1362,7 +1362,7 @@ static inline void convert_VkSwapchainCreateInfoKHR_win_to_host(const VkSwapchai
 #version 450
 
 layout(binding = 0) uniform sampler2D texSampler;
-layout(binding = 1, rgba8) uniform writeonly image2D outImage;
+layout(binding = 1) uniform writeonly image2D outImage;
 layout(push_constant) uniform pushConstants {
     //both in real image coords
     vec2 offset;
@@ -1375,57 +1375,45 @@ void main()
 {
     vec2 texcoord = (vec2(gl_GlobalInvocationID.xy) - constants.offset) / constants.extents;
     vec4 c = texture(texSampler, texcoord);
-    imageStore(outImage, ivec2(gl_GlobalInvocationID.xy), c.bgra);
+    imageStore(outImage, ivec2(gl_GlobalInvocationID.xy), c);
 }
 */
 const uint32_t blit_comp_spv[] = {
-	0x07230203,0x00010000,0x00080006,0x00000037,0x00000000,0x00020011,0x00000001,0x0006000b,
-	0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
-	0x0006000f,0x00000005,0x00000004,0x6e69616d,0x00000000,0x0000000d,0x00060010,0x00000004,
-	0x00000011,0x00000008,0x00000008,0x00000001,0x00030003,0x00000002,0x000001c2,0x00040005,
-	0x00000004,0x6e69616d,0x00000000,0x00050005,0x00000009,0x63786574,0x64726f6f,0x00000000,
-	0x00080005,0x0000000d,0x475f6c67,0x61626f6c,0x766e496c,0x7461636f,0x496e6f69,0x00000044,
-	0x00060005,0x00000012,0x68737570,0x736e6f43,0x746e6174,0x00000073,0x00050006,0x00000012,
-	0x00000000,0x7366666f,0x00007465,0x00050006,0x00000012,0x00000001,0x65747865,0x0073746e,
-	0x00050005,0x00000014,0x736e6f63,0x746e6174,0x00000073,0x00030005,0x00000021,0x00000063,
-	0x00050005,0x00000025,0x53786574,0x6c706d61,0x00007265,0x00050005,0x0000002c,0x4974756f,
-	0x6567616d,0x00000000,0x00040047,0x0000000d,0x0000000b,0x0000001c,0x00050048,0x00000012,
-	0x00000000,0x00000023,0x00000000,0x00050048,0x00000012,0x00000001,0x00000023,0x00000008,
-	0x00030047,0x00000012,0x00000002,0x00040047,0x00000025,0x00000022,0x00000000,0x00040047,
-	0x00000025,0x00000021,0x00000000,0x00040047,0x0000002c,0x00000022,0x00000000,0x00040047,
-	0x0000002c,0x00000021,0x00000001,0x00030047,0x0000002c,0x00000019,0x00040047,0x00000036,
-	0x0000000b,0x00000019,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,
-	0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000002,0x00040020,0x00000008,
-	0x00000007,0x00000007,0x00040015,0x0000000a,0x00000020,0x00000000,0x00040017,0x0000000b,
-	0x0000000a,0x00000003,0x00040020,0x0000000c,0x00000001,0x0000000b,0x0004003b,0x0000000c,
-	0x0000000d,0x00000001,0x00040017,0x0000000e,0x0000000a,0x00000002,0x0004001e,0x00000012,
-	0x00000007,0x00000007,0x00040020,0x00000013,0x00000009,0x00000012,0x0004003b,0x00000013,
-	0x00000014,0x00000009,0x00040015,0x00000015,0x00000020,0x00000001,0x0004002b,0x00000015,
-	0x00000016,0x00000000,0x00040020,0x00000017,0x00000009,0x00000007,0x0004002b,0x00000015,
-	0x0000001b,0x00000001,0x00040017,0x0000001f,0x00000006,0x00000004,0x00040020,0x00000020,
-	0x00000007,0x0000001f,0x00090019,0x00000022,0x00000006,0x00000001,0x00000000,0x00000000,
-	0x00000000,0x00000001,0x00000000,0x0003001b,0x00000023,0x00000022,0x00040020,0x00000024,
-	0x00000000,0x00000023,0x0004003b,0x00000024,0x00000025,0x00000000,0x0004002b,0x00000006,
-	0x00000028,0x00000000,0x00090019,0x0000002a,0x00000006,0x00000001,0x00000000,0x00000000,
-	0x00000000,0x00000002,0x00000004,0x00040020,0x0000002b,0x00000000,0x0000002a,0x0004003b,
-	0x0000002b,0x0000002c,0x00000000,0x00040017,0x00000030,0x00000015,0x00000002,0x0004002b,
-	0x0000000a,0x00000034,0x00000008,0x0004002b,0x0000000a,0x00000035,0x00000001,0x0006002c,
-	0x0000000b,0x00000036,0x00000034,0x00000034,0x00000035,0x00050036,0x00000002,0x00000004,
-	0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000008,0x00000009,0x00000007,
-	0x0004003b,0x00000020,0x00000021,0x00000007,0x0004003d,0x0000000b,0x0000000f,0x0000000d,
-	0x0007004f,0x0000000e,0x00000010,0x0000000f,0x0000000f,0x00000000,0x00000001,0x00040070,
-	0x00000007,0x00000011,0x00000010,0x00050041,0x00000017,0x00000018,0x00000014,0x00000016,
-	0x0004003d,0x00000007,0x00000019,0x00000018,0x00050083,0x00000007,0x0000001a,0x00000011,
-	0x00000019,0x00050041,0x00000017,0x0000001c,0x00000014,0x0000001b,0x0004003d,0x00000007,
-	0x0000001d,0x0000001c,0x00050088,0x00000007,0x0000001e,0x0000001a,0x0000001d,0x0003003e,
-	0x00000009,0x0000001e,0x0004003d,0x00000023,0x00000026,0x00000025,0x0004003d,0x00000007,
-	0x00000027,0x00000009,0x00070058,0x0000001f,0x00000029,0x00000026,0x00000027,0x00000002,
-	0x00000028,0x0003003e,0x00000021,0x00000029,0x0004003d,0x0000002a,0x0000002d,0x0000002c,
-	0x0004003d,0x0000000b,0x0000002e,0x0000000d,0x0007004f,0x0000000e,0x0000002f,0x0000002e,
-	0x0000002e,0x00000000,0x00000001,0x0004007c,0x00000030,0x00000031,0x0000002f,0x0004003d,
-	0x0000001f,0x00000032,0x00000021,0x0009004f,0x0000001f,0x00000033,0x00000032,0x00000032,
-	0x00000002,0x00000001,0x00000000,0x00000003,0x00040063,0x0000002d,0x00000031,0x00000033,
-	0x000100fd,0x00010038
+    0x07230203, 0x00010000, 0x00080008, 0x00000036, 0x00000000, 0x00020011, 0x00000001, 0x00020011, 0x00000038,
+    0x0006000B, 0x00000001, 0x4C534C47, 0x6474732E, 0x3035342E, 0x00000000, 0x0003000E, 0x00000000, 0x00000001,
+    0x0006000F, 0x00000005, 0x00000004, 0x6E69616D, 0x00000000, 0x0000000D, 0x00060010, 0x00000004, 0x00000011,
+    0x00000008, 0x00000008, 0x00000001, 0x00030003, 0x00000002, 0x000001C2, 0x00040005, 0x00000004, 0x6E69616D,
+    0x00000000, 0x00080005, 0x0000000D, 0x475F6C67, 0x61626F6C, 0x766E496C, 0x7461636F, 0x496E6F69, 0x00000044,
+    0x00060005, 0x00000012, 0x68737570, 0x736E6F43, 0x746E6174, 0x00000073, 0x00050006, 0x00000012, 0x00000000,
+    0x7366666F, 0x00007465, 0x00050006, 0x00000012, 0x00000001, 0x65747865, 0x0073746E, 0x00050005, 0x00000014,
+    0x736E6F63, 0x746E6174, 0x00000073, 0x00050005, 0x00000025, 0x53786574, 0x6C706D61, 0x00007265, 0x00050005,
+    0x0000002C, 0x4974756F, 0x6567616D, 0x00000000, 0x00040047, 0x0000000D, 0x0000000B, 0x0000001C, 0x00050048,
+    0x00000012, 0x00000000, 0x00000023, 0x00000000, 0x00050048, 0x00000012, 0x00000001, 0x00000023, 0x00000008,
+    0x00030047, 0x00000012, 0x00000002, 0x00040047, 0x00000025, 0x00000022, 0x00000000, 0x00040047, 0x00000025,
+    0x00000021, 0x00000000, 0x00040047, 0x0000002C, 0x00000022, 0x00000000, 0x00040047, 0x0000002C, 0x00000021,
+    0x00000001, 0x00030047, 0x0000002C, 0x00000019, 0x00040047, 0x00000035, 0x0000000B, 0x00000019, 0x00020013,
+    0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00030016, 0x00000006, 0x00000020, 0x00040017, 0x00000007,
+    0x00000006, 0x00000002, 0x00040015, 0x0000000A, 0x00000020, 0x00000000, 0x00040017, 0x0000000B, 0x0000000A,
+    0x00000003, 0x00040020, 0x0000000C, 0x00000001, 0x0000000B, 0x0004003B, 0x0000000C, 0x0000000D, 0x00000001,
+    0x00040017, 0x0000000E, 0x0000000A, 0x00000002, 0x0004001E, 0x00000012, 0x00000007, 0x00000007, 0x00040020,
+    0x00000013, 0x00000009, 0x00000012, 0x0004003B, 0x00000013, 0x00000014, 0x00000009, 0x00040015, 0x00000015,
+    0x00000020, 0x00000001, 0x0004002B, 0x00000015, 0x00000016, 0x00000000, 0x00040020, 0x00000017, 0x00000009,
+    0x00000007, 0x0004002B, 0x00000015, 0x0000001B, 0x00000001, 0x00040017, 0x0000001F, 0x00000006, 0x00000004,
+    0x00090019, 0x00000022, 0x00000006, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000,
+    0x0003001B, 0x00000023, 0x00000022, 0x00040020, 0x00000024, 0x00000000, 0x00000023, 0x0004003B, 0x00000024,
+    0x00000025, 0x00000000, 0x0004002B, 0x00000006, 0x00000028, 0x00000000, 0x00090019, 0x0000002A, 0x00000006,
+    0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0x00000000, 0x00040020, 0x0000002B, 0x00000000,
+    0x0000002A, 0x0004003B, 0x0000002B, 0x0000002C, 0x00000000, 0x00040017, 0x00000030, 0x00000015, 0x00000002,
+    0x0004002B, 0x0000000A, 0x00000033, 0x00000008, 0x0004002B, 0x0000000A, 0x00000034, 0x00000001, 0x0006002C,
+    0x0000000B, 0x00000035, 0x00000033, 0x00000033, 0x00000034, 0x00050036, 0x00000002, 0x00000004, 0x00000000,
+    0x00000003, 0x000200F8, 0x00000005, 0x0004003D, 0x0000000B, 0x0000000F, 0x0000000D, 0x0007004F, 0x0000000E,
+    0x00000010, 0x0000000F, 0x0000000F, 0x00000000, 0x00000001, 0x00040070, 0x00000007, 0x00000011, 0x00000010,
+    0x00050041, 0x00000017, 0x00000018, 0x00000014, 0x00000016, 0x0004003D, 0x00000007, 0x00000019, 0x00000018,
+    0x00050083, 0x00000007, 0x0000001A, 0x00000011, 0x00000019, 0x00050041, 0x00000017, 0x0000001C, 0x00000014,
+    0x0000001B, 0x0004003D, 0x00000007, 0x0000001D, 0x0000001C, 0x00050088, 0x00000007, 0x0000001E, 0x0000001A,
+    0x0000001D, 0x0004003D, 0x00000023, 0x00000026, 0x00000025, 0x00070058, 0x0000001F, 0x00000029, 0x00000026,
+    0x0000001E, 0x00000002, 0x00000028, 0x0004003D, 0x0000002A, 0x0000002D, 0x0000002C, 0x0004007C, 0x00000030,
+    0x00000031, 0x00000010, 0x00040063, 0x0000002D, 0x00000031, 0x00000029, 0x000100FD, 0x00010038
 };
 
 static VkResult create_pipeline(VkDevice device, struct VkSwapchainKHR_T *swapchain, struct fs_hack_image *hack, VkShaderModule shaderModule)
@@ -1739,12 +1727,13 @@ VkResult WINAPI wine_vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCrea
         TRACE("surface usage flags: 0x%x\n", object->surface_usage);
 
         our_createinfo.imageExtent = object->real_extent;
-        our_createinfo.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; /* XXX: check if supported by surface */
+        our_createinfo.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT | (object->surface_usage & VK_IMAGE_USAGE_STORAGE_BIT); /* XXX: check if supported by surface */
 
         if(our_createinfo.imageFormat != VK_FORMAT_B8G8R8A8_UNORM &&
                 our_createinfo.imageFormat != VK_FORMAT_B8G8R8A8_SRGB){
             FIXME("swapchain image format is not BGRA8 UNORM/SRGB. Things may go badly. %d\n", our_createinfo.imageFormat);
         }
+        object->imageFormat = our_createinfo.imageFormat;
 
         object->fs_hack_enabled = TRUE;
     }
@@ -2035,7 +2024,7 @@ static VkResult init_blit_images(VkDevice device, struct VkSwapchainKHR_T *swapc
             imageInfo.extent.depth = 1;
             imageInfo.mipLevels = 1;
             imageInfo.arrayLayers = 1;
-            imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
+            imageInfo.format = swapchain->imageFormat;
             imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
             imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
             imageInfo.usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
@@ -2123,7 +2112,7 @@ static VkResult init_blit_images(VkDevice device, struct VkSwapchainKHR_T *swapc
         viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
         viewInfo.image = hack->blit_image ? hack->blit_image : hack->swapchain_image;
         viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
-        viewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
+        viewInfo.format = swapchain->imageFormat;
         viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
         viewInfo.subresourceRange.baseMipLevel = 0;
         viewInfo.subresourceRange.levelCount = 1;
diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h
index ea2501ebc68..d5a0369608e 100644
--- a/dlls/winevulkan/vulkan_private.h
+++ b/dlls/winevulkan/vulkan_private.h
@@ -178,6 +178,7 @@ struct VkSwapchainKHR_T
     uint32_t n_images;
     struct fs_hack_image *fs_hack_images; /* struct fs_hack_image[n_images] */
     VkFilter fs_hack_filter;
+    VkFormat imageFormat;
     VkSampler sampler;
     VkDescriptorPool descriptor_pool;
     VkDescriptorSetLayout descriptor_set_layout;
From 2478cd397f466ad3348f096a08c4c46b565497fe Mon Sep 17 00:00:00 2001
From: Joshua Ashton <joshua@froggi.es>
Date: Thu, 5 Mar 2020 15:53:05 +0000
Subject: [PATCH] winevulkan: Use alloca for vkCmdExecuteCommands

---
 dlls/winevulkan/vulkan.c | 13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)

diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
index 920f203d830..f989388d7ce 100644
--- a/dlls/winevulkan/vulkan.c
+++ b/dlls/winevulkan/vulkan.c
@@ -511,23 +511,12 @@ void WINAPI wine_vkCmdExecuteCommands(VkCommandBuffer buffer, uint32_t count,
     if (!buffers || !count)
         return;
 
-    /* Unfortunately we need a temporary buffer as our command buffers are wrapped.
-     * This call is called often and if a performance concern, we may want to use
-     * alloca as we shouldn't need much memory and it needs to be cleaned up after
-     * the call anyway.
-     */
-    if (!(tmp_buffers = heap_alloc(count * sizeof(*tmp_buffers))))
-    {
-        ERR("Failed to allocate memory for temporary command buffers\n");
-        return;
-    }
+    tmp_buffers = WINEVULKAN_ALLOCA(count * sizeof(*tmp_buffers));
 
     for (i = 0; i < count; i++)
         tmp_buffers[i] = buffers[i]->command_buffer;
 
     buffer->device->funcs.p_vkCmdExecuteCommands(buffer->command_buffer, count, tmp_buffers);
-
-    heap_free(tmp_buffers);
 }
 
 VkResult WINAPI wine_vkCreateDevice(VkPhysicalDevice phys_dev,
From 1f350c3deec385bdec51f712748f144dd3219401 Mon Sep 17 00:00:00 2001
From: Joshua Ashton <joshua@froggi.es>
Date: Thu, 5 Mar 2020 15:54:25 +0000
Subject: [PATCH] winevulkan: Remove unnecessary check for buffers and count in
 vkCmdExecuteCommands

The Vulkan spec states commandBufferCount must be greater than zero and pCommandBuffers must be a valid pointer.
---
 dlls/winevulkan/vulkan.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
index f989388d7ce..508869e66b5 100644
--- a/dlls/winevulkan/vulkan.c
+++ b/dlls/winevulkan/vulkan.c
@@ -508,9 +508,6 @@ void WINAPI wine_vkCmdExecuteCommands(VkCommandBuffer buffer, uint32_t count,
 
     TRACE("%p %u %p\n", buffer, count, buffers);
 
-    if (!buffers || !count)
-        return;
-
     tmp_buffers = WINEVULKAN_ALLOCA(count * sizeof(*tmp_buffers));
 
     for (i = 0; i < count; i++)
From 17203ba38d89d9c32d84eb40b50dd672939f6712 Mon Sep 17 00:00:00 2001
From: Joshua Ashton <joshua@froggi.es>
Date: Thu, 5 Mar 2020 16:01:19 +0000
Subject: [PATCH] winevulkan: Use alloca for swapchain buffers

---
 dlls/winevulkan/vulkan.c | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
index 508869e66b5..22a819ed2b9 100644
--- a/dlls/winevulkan/vulkan.c
+++ b/dlls/winevulkan/vulkan.c
@@ -2649,11 +2649,7 @@ VkResult WINAPI wine_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pP
         our_presentInfo.pWaitSemaphores = &blit_sema;
     }
 
-    arr = heap_alloc(our_presentInfo.swapchainCount * sizeof(VkSwapchainKHR));
-    if(!arr){
-        ERR("Failed to allocate memory for swapchain array\n");
-        return VK_ERROR_OUT_OF_HOST_MEMORY;
-    }
+    arr = WINEVULKAN_ALLOCA(our_presentInfo.swapchainCount * sizeof(VkSwapchainKHR));
 
     for(i = 0; i < our_presentInfo.swapchainCount; ++i)
         arr[i] = ((struct VkSwapchainKHR_T *)(UINT_PTR)our_presentInfo.pSwapchains[i])->swapchain;
@@ -2662,8 +2658,6 @@ VkResult WINAPI wine_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pP
 
     res = queue->device->funcs.p_vkQueuePresentKHR(queue->queue, &our_presentInfo);
 
-    heap_free(arr);
-
     return res;
 
 }
From 378b72afd71a3d0ca2809d3b95ecf295946b84ab Mon Sep 17 00:00:00 2001
From: Joshua Ashton <joshua@froggi.es>
Date: Thu, 12 Mar 2020 23:40:38 +0000
Subject: [PATCH] winevulkan: Implement VK_KHR_get_surface_capabilities2 and
 fake support for VK_EXT_full_screen_exclusive

---
 dlls/vulkan-1/vulkan-1.spec      |   2 +
 dlls/winevulkan/make_vulkan      |  50 +++++++-
 dlls/winevulkan/vulkan.c         | 125 ++++++++++++++++++
 dlls/winevulkan/vulkan_private.h |   4 +
 dlls/winevulkan/vulkan_thunks.c  |  77 ++++++++++-
 dlls/winevulkan/vulkan_thunks.h  |  47 +++++++
 dlls/winevulkan/winevulkan.spec  |   2 +
 dlls/winex11.drv/vulkan.c        |  34 +++++
 include/wine/vulkan.h            | 212 +++++++++++++++++++++----------
 include/wine/vulkan_driver.h     |   8 +-
 10 files changed, 482 insertions(+), 79 deletions(-)

diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan
index b58ca9301cc..e6291d87efa 100755
--- a/dlls/winevulkan/make_vulkan
+++ b/dlls/winevulkan/make_vulkan
@@ -95,7 +95,6 @@ BLACKLISTED_EXTENSIONS = [
     "VK_AMD_display_native_hdr",
     "VK_EXT_calibrated_timestamps",
     "VK_EXT_display_control", # Requires VK_EXT_display_surface_counter
-    "VK_EXT_full_screen_exclusive",
     "VK_EXT_hdr_metadata", # Needs WSI work.
     "VK_EXT_pipeline_creation_feedback",
     "VK_GOOGLE_display_timing",
@@ -133,6 +131,11 @@ CORE_EXTENSIONS = [
     "VK_KHR_surface",
     "VK_KHR_swapchain",
     "VK_KHR_win32_surface",
+    "VK_KHR_get_surface_capabilities2",
+]
+
+FAKED_EXTENSIONS = [
+    {"name": "VK_EXT_full_screen_exclusive", "version": 4}
 ]
 
 # Functions part of our winevulkan graphics driver interface.
@@ -183,7 +186,7 @@ FUNCTION_OVERRIDES = {
     "vkGetPhysicalDeviceSurfaceSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
     "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" : {"dispatch" : True, "driver" : True, "thunk" : False, "private_thunk" : True},
     "vkGetPhysicalDeviceSurfaceFormatsKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
-    "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
+    "vkGetPhysicalDeviceSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True, "private_thunk" : True},
 
     # VK_KHR_win32_surface
     "vkCreateWin32SurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
@@ -210,8 +213,18 @@ FUNCTION_OVERRIDES = {
     "vkEnumeratePhysicalDeviceGroupsKHR" : {"dispatch" : True, "driver" : False, "thunk" : False},
 
     # VK_KHR_device_group
-    "vkGetDeviceGroupSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
+    "vkGetDeviceGroupSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True, "private_thunk": True},
     "vkGetPhysicalDevicePresentRectanglesKHR" : {"dispatch" : True, "driver" : True, "thunk" : True},
+
+    # VK_KHR_get_surface_capabilities2
+    #"vkGetPhysicalDeviceSurfaceCapabilities2KHR" : {"dispatch" : True, "driver" : True, "thunk" : False, "private_thunk" : True},
+    #"vkGetPhysicalDeviceSurfaceFormats2KHR" : {"dispatch" : True, "driver" : True, "thunk" : False, "private_thunk" : True},
+
+    # VK_EXT_full_screen_exclusive
+    "vkGetPhysicalDeviceSurfacePresentModes2EXT" : {"dispatch" : True, "driver" : False, "thunk" : False},
+    "vkGetDeviceGroupSurfacePresentModes2EXT" : {"dispatch" : True, "driver" : False, "thunk" : False},
+    "vkAcquireFullScreenExclusiveModeEXT" : {"dispatch" : True, "driver" : False, "thunk" : False},
+    "vkReleaseFullScreenExclusiveModeEXT" : {"dispatch" : True, "driver" : False, "thunk" : False},
 }
 
 STRUCT_CHAIN_CONVERSIONS = [
@@ -2241,6 +2254,12 @@ class VkGenerator(object):
             f.write("    \"{0}\",\n".format(ext["name"]))
         f.write("};\n\n")
 
+        # Create array of faked device extensions.
+        f.write("static const VkExtensionProperties vk_device_extension_discards[] =\n{\n")
+        for ext in FAKED_EXTENSIONS:
+            f.write("    {{\"{0}\", {1}}},\n".format(ext["name"], ext["version"]))
+        f.write("};\n\n")
+
         # Create array of instance extensions.
         f.write("static const char * const vk_instance_extensions[] =\n{\n")
         for ext in self.registry.extensions:
@@ -2261,6 +2280,27 @@ class VkGenerator(object):
         f.write("    return FALSE;\n")
         f.write("}\n\n")
 
+        f.write("BOOL wine_vk_device_extension_faked(const char *name)\n")
+        f.write("{\n")
+        f.write("    unsigned int i;\n")
+        f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_extension_discards); i++)\n")
+        f.write("    {\n")
+        f.write("        if (strcmp(vk_device_extension_discards[i].extensionName, name) == 0)\n")
+        f.write("            return TRUE;\n")
+        f.write("    }\n")
+        f.write("    return FALSE;\n")
+        f.write("}\n\n")
+
+        f.write("unsigned int wine_vk_device_extension_faked_count(void)\n")
+        f.write("{\n")
+        f.write("    return ARRAY_SIZE(vk_device_extension_discards);\n")
+        f.write("}\n\n")
+
+        f.write("const VkExtensionProperties* wine_vk_device_extension_faked_idx(unsigned int idx)\n")
+        f.write("{\n")
+        f.write("    return &vk_device_extension_discards[idx];\n")
+        f.write("}\n\n")
+
         f.write("BOOL wine_vk_instance_extension_supported(const char *name)\n")
         f.write("{\n")
         f.write("    unsigned int i;\n")
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
index e2991c2dc47..1e730a415bc 100644
--- a/dlls/winevulkan/vulkan.c
+++ b/dlls/winevulkan/vulkan.c
@@ -121,6 +121,8 @@ static struct VkPhysicalDevice_T *wine_vk_physical_device_alloc(struct VkInstanc
         }
     }
 
+    num_properties += wine_vk_device_extension_faked_count();
+
     TRACE("Host supported extensions %u, Wine supported extensions %u\n", num_host_properties, num_properties);
 
     if (!(object->extensions = heap_calloc(num_properties, sizeof(*object->extensions))))
@@ -137,6 +139,13 @@ static struct VkPhysicalDevice_T *wine_vk_physical_device_alloc(struct VkInstanc
             j++;
         }
     }
+
+    for (i = 0; i < wine_vk_device_extension_faked_count(); i++)
+    {
+        object->extensions[j] = *wine_vk_device_extension_faked_idx(i);
+        j++;
+    }
+
     object->extension_count = num_properties;
 
     heap_free(host_properties);
@@ -217,6 +226,8 @@ static void wine_vk_device_free_create_info(VkDeviceCreateInfo *create_info)
         heap_free((void *)group_info->pPhysicalDevices);
     }
 
+    heap_free((void *)create_info->ppEnabledExtensionNames);
+
     free_VkDeviceCreateInfo_struct_chain(create_info);
 }
 
@@ -226,6 +237,7 @@ static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src
     VkDeviceGroupDeviceCreateInfo *group_info;
     unsigned int i;
     VkResult res;
+    const char** extensions;
 
     *dst = *src;
 
@@ -252,6 +264,18 @@ static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src
         group_info->pPhysicalDevices = physical_devices;
     }
 
+    extensions = heap_alloc(sizeof(const char*) * src->enabledExtensionCount);
+    dst->ppEnabledExtensionNames = extensions;
+    dst->enabledExtensionCount = 0;
+    for (i = 0; i < src->enabledExtensionCount; i++) {
+        const char *extension_name = src->ppEnabledExtensionNames[i];
+
+        if (!wine_vk_device_extension_faked(extension_name)) {
+            extensions[dst->enabledExtensionCount] = extension_name;
+            dst->enabledExtensionCount++;
+        }
+    }
+
     /* Should be filtered out by loader as ICDs don't support layers. */
     dst->enabledLayerCount = 0;
     dst->ppEnabledLayerNames = NULL;
@@ -1035,6 +1059,59 @@ VkResult WINAPI wine_vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t *supported_version)
     return VK_SUCCESS;
 }
 
+/* VK_EXT_full_screen_exclusive */
+
+VkResult WINAPI wine_vkGetPhysicalDeviceSurfacePresentModes2EXT(
+    VkPhysicalDevice                            physicalDevice,
+    const VkPhysicalDeviceSurfaceInfo2KHR*      pSurfaceInfo,
+    uint32_t*                                   pPresentModeCount,
+    VkPresentModeKHR*                           pPresentModes)
+{
+    TRACE("%p, %p, %p, %p", physicalDevice, pSurfaceInfo, pPresentModeCount, pPresentModes);
+    return thunk_vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, pSurfaceInfo->surface, pPresentModeCount, pPresentModes);
+}
+
+VkResult WINAPI wine_vkGetDeviceGroupSurfacePresentModes2EXT(
+    VkDevice                                    device,
+    const VkPhysicalDeviceSurfaceInfo2KHR*      pSurfaceInfo,
+    VkDeviceGroupPresentModeFlagsKHR*           pModes)
+{
+    TRACE("%p, %p, %p", device, pSurfaceInfo, pModes);
+    return thunk_vkGetDeviceGroupSurfacePresentModesKHR(device, pSurfaceInfo->surface, pModes);
+}
+
+VkResult WINAPI wine_vkAcquireFullScreenExclusiveModeEXT(
+    VkDevice                                    device,
+    VkSwapchainKHR                              swapchain)
+{
+    /* don't care */
+    TRACE("%p, %s", device, wine_dbgstr_longlong(swapchain));
+
+    return VK_SUCCESS;
+}
+
+VkResult WINAPI wine_vkReleaseFullScreenExclusiveModeEXT(
+    VkDevice                                    device,
+    VkSwapchainKHR                              swapchain)
+{
+    /* don't care */
+    TRACE("%p, %s", device, wine_dbgstr_longlong(swapchain));
+
+    return VK_SUCCESS;
+}
+
+/* extra crap we moved to private thunks */
+
+VkResult WINAPI wine_vkGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR *pModes)
+{
+    return thunk_vkGetDeviceGroupSurfacePresentModesKHR(device, surface, pModes);
+}
+
+VkResult WINAPI wine_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes)
+{
+    return thunk_vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, pPresentModeCount, pPresentModes);
+}
+
 VkResult WINAPI wine_vkQueueSubmit(VkQueue queue, uint32_t count,
         const VkSubmitInfo *submits, VkFence fence)
 {
diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h
index 001ce85a1fd..0d9c9b9dc23 100644
--- a/dlls/winevulkan/vulkan_private.h
+++ b/dlls/winevulkan/vulkan_private.h
@@ -175,6 +175,10 @@ struct VkSwapchainKHR_T
 void *wine_vk_get_device_proc_addr(const char *name) DECLSPEC_HIDDEN;
 void *wine_vk_get_instance_proc_addr(const char *name) DECLSPEC_HIDDEN;
 
+BOOL wine_vk_device_extension_faked(const char *name) DECLSPEC_HIDDEN;
+unsigned int wine_vk_device_extension_faked_count(void) DECLSPEC_HIDDEN;
+const VkExtensionProperties* wine_vk_device_extension_faked_idx(unsigned int idx) DECLSPEC_HIDDEN;
+
 BOOL wine_vk_device_extension_supported(const char *name) DECLSPEC_HIDDEN;
 BOOL wine_vk_instance_extension_supported(const char *name) DECLSPEC_HIDDEN;
 
diff --git a/dlls/winevulkan/vulkan_thunks.c b/dlls/winevulkan/vulkan_thunks.c
index ea9e8262d83..bd304556617 100644
--- a/dlls/winevulkan/vulkan_thunks.c
+++ b/dlls/winevulkan/vulkan_thunks.c
@@ -3770,9 +3779,8 @@ VkResult WINAPI wine_vkGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkD
     return device->funcs.p_vkGetDeviceGroupPresentCapabilitiesKHR(device->device, pDeviceGroupPresentCapabilities);
 }
 
-VkResult WINAPI wine_vkGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR *pModes)
+VkResult thunk_vkGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR *pModes)
 {
-    TRACE("%p, 0x%s, %p\n", device, wine_dbgstr_longlong(surface), pModes);
     return device->funcs.p_vkGetDeviceGroupSurfacePresentModesKHR(device->device, surface, pModes);
 }
 
@@ -4145,9 +4153,8 @@ static VkResult WINAPI wine_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesC
     return physicalDevice->instance->funcs.p_vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice->phys_dev, surface, pSurfaceFormatCount, pSurfaceFormats);
 }
 
-VkResult WINAPI wine_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes)
+VkResult thunk_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes)
 {
-    TRACE("%p, 0x%s, %p, %p\n", physicalDevice, wine_dbgstr_longlong(surface), pPresentModeCount, pPresentModes);
     return physicalDevice->instance->funcs.p_vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice->phys_dev, surface, pPresentModeCount, pPresentModes);
 }
 
@@ -4479,6 +4514,7 @@ static VkResult WINAPI wine_vkWaitSemaphoresKHR(VkDevice device, const VkSemapho
 
 static const struct vulkan_func vk_device_dispatch_table[] =
 {
+    {"vkAcquireFullScreenExclusiveModeEXT", &wine_vkAcquireFullScreenExclusiveModeEXT},
     {"vkAcquireNextImage2KHR", &wine_vkAcquireNextImage2KHR},
     {"vkAcquireNextImageKHR", &wine_vkAcquireNextImageKHR},
     {"vkAcquirePerformanceConfigurationINTEL", &wine_vkAcquirePerformanceConfigurationINTEL},
@@ -4650,6 +4686,7 @@ static const struct vulkan_func vk_device_dispatch_table[] =
     {"vkGetDeviceGroupPeerMemoryFeatures", &wine_vkGetDeviceGroupPeerMemoryFeatures},
     {"vkGetDeviceGroupPeerMemoryFeaturesKHR", &wine_vkGetDeviceGroupPeerMemoryFeaturesKHR},
     {"vkGetDeviceGroupPresentCapabilitiesKHR", &wine_vkGetDeviceGroupPresentCapabilitiesKHR},
+    {"vkGetDeviceGroupSurfacePresentModes2EXT", &wine_vkGetDeviceGroupSurfacePresentModes2EXT},
     {"vkGetDeviceGroupSurfacePresentModesKHR", &wine_vkGetDeviceGroupSurfacePresentModesKHR},
     {"vkGetDeviceMemoryCommitment", &wine_vkGetDeviceMemoryCommitment},
     {"vkGetDeviceProcAddr", &wine_vkGetDeviceProcAddr},
@@ -4688,6 +4725,7 @@ static const struct vulkan_func vk_device_dispatch_table[] =
     {"vkQueueSetPerformanceConfigurationINTEL", &wine_vkQueueSetPerformanceConfigurationINTEL},
     {"vkQueueSubmit", &wine_vkQueueSubmit},
     {"vkQueueWaitIdle", &wine_vkQueueWaitIdle},
+    {"vkReleaseFullScreenExclusiveModeEXT", &wine_vkReleaseFullScreenExclusiveModeEXT},
     {"vkReleasePerformanceConfigurationINTEL", &wine_vkReleasePerformanceConfigurationINTEL},
     {"vkResetCommandBuffer", &wine_vkResetCommandBuffer},
     {"vkResetCommandPool", &wine_vkResetCommandPool},
@@ -4751,6 +4789,7 @@ static const struct vulkan_func vk_instance_dispatch_table[] =
     {"vkGetPhysicalDeviceSurfaceCapabilitiesKHR", &wine_vkGetPhysicalDeviceSurfaceCapabilitiesKHR},
     {"vkGetPhysicalDeviceSurfaceFormats2KHR", &wine_vkGetPhysicalDeviceSurfaceFormats2KHR},
     {"vkGetPhysicalDeviceSurfaceFormatsKHR", &wine_vkGetPhysicalDeviceSurfaceFormatsKHR},
+    {"vkGetPhysicalDeviceSurfacePresentModes2EXT", &wine_vkGetPhysicalDeviceSurfacePresentModes2EXT},
     {"vkGetPhysicalDeviceSurfacePresentModesKHR", &wine_vkGetPhysicalDeviceSurfacePresentModesKHR},
     {"vkGetPhysicalDeviceSurfaceSupportKHR", &wine_vkGetPhysicalDeviceSurfaceSupportKHR},
     {"vkGetPhysicalDeviceToolPropertiesEXT", &wine_vkGetPhysicalDeviceToolPropertiesEXT},
@@ -4821,6 +4862,7 @@ static const char * const vk_device_extensions[] =
     "VK_EXT_filter_cubic",
     "VK_EXT_fragment_density_map",
     "VK_EXT_fragment_shader_interlock",
+    "VK_EXT_full_screen_exclusive",
     "VK_EXT_global_priority",
     "VK_EXT_host_query_reset",
     "VK_EXT_index_type_uint8",
@@ -4921,6 +4963,11 @@ static const char * const vk_device_extensions[] =
     "VK_NV_viewport_swizzle",
 };
 
+static const VkExtensionProperties vk_device_extension_discards[] =
+{
+    {"VK_EXT_full_screen_exclusive", 4},
+};
+
 static const char * const vk_instance_extensions[] =
 {
     "VK_EXT_headless_surface",
@@ -4945,6 +4993,27 @@ BOOL wine_vk_device_extension_supported(const char *name)
     return FALSE;
 }
 
+BOOL wine_vk_device_extension_faked(const char *name)
+{
+    unsigned int i;
+    for (i = 0; i < ARRAY_SIZE(vk_device_extension_discards); i++)
+    {
+        if (strcmp(vk_device_extension_discards[i].extensionName, name) == 0)
+            return TRUE;
+    }
+    return FALSE;
+}
+
+unsigned int wine_vk_device_extension_faked_count(void)
+{
+    return ARRAY_SIZE(vk_device_extension_discards);
+}
+
+const VkExtensionProperties* wine_vk_device_extension_faked_idx(unsigned int idx)
+{
+    return &vk_device_extension_discards[idx];
+}
+
 BOOL wine_vk_instance_extension_supported(const char *name)
 {
     unsigned int i;
diff --git a/dlls/winevulkan/vulkan_thunks.h b/dlls/winevulkan/vulkan_thunks.h
index 82d0c3a0a5e..8da14348c18 100644
--- a/dlls/winevulkan/vulkan_thunks.h
+++ b/dlls/winevulkan/vulkan_thunks.h
@@ -41,6 +41,7 @@
 #define WINE_VK_VERSION VK_API_VERSION_1_2
 
 /* Functions for which we have custom implementations outside of the thunks. */
+VkResult WINAPI wine_vkAcquireFullScreenExclusiveModeEXT(VkDevice device, VkSwapchainKHR swapchain) DECLSPEC_HIDDEN;
 VkResult WINAPI wine_vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex);
 VkResult WINAPI wine_vkAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo, VkCommandBuffer *pCommandBuffers);
 void WINAPI wine_vkCmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers);
@@ -56,6 +57,8 @@ VkResult WINAPI wine_vkEnumeratePhysicalDeviceGroups(VkInstance instance, uint32
 VkResult WINAPI wine_vkEnumeratePhysicalDeviceGroupsKHR(VkInstance instance, uint32_t *pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties) DECLSPEC_HIDDEN;
 VkResult WINAPI wine_vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices);
 void WINAPI wine_vkFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers);
+VkResult WINAPI wine_vkGetDeviceGroupSurfacePresentModes2EXT(VkDevice device, const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, VkDeviceGroupPresentModeFlagsKHR *pModes) DECLSPEC_HIDDEN;
+VkResult WINAPI wine_vkGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR *pModes);
 PFN_vkVoidFunction WINAPI wine_vkGetDeviceProcAddr(VkDevice device, const char *pName);
 void WINAPI wine_vkGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue);
 void WINAPI wine_vkGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 *pQueueInfo, VkQueue *pQueue);
@@ -67,14 +70,19 @@ void WINAPI wine_vkGetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice
 VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, VkImageFormatProperties2 *pImageFormatProperties);
 VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, VkImageFormatProperties2 *pImageFormatProperties) DECLSPEC_HIDDEN;
 VkResult WINAPI wine_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *pSurfaceCapabilities);
+VkResult WINAPI wine_vkGetPhysicalDeviceSurfacePresentModes2EXT(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes) DECLSPEC_HIDDEN;
+VkResult WINAPI wine_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes);
 VkResult WINAPI wine_vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages);
 VkResult WINAPI wine_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo);
 VkResult WINAPI wine_vkQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence);
+VkResult WINAPI wine_vkReleaseFullScreenExclusiveModeEXT(VkDevice device, VkSwapchainKHR swapchain) DECLSPEC_HIDDEN;
 
 /* Private thunks */
+VkResult thunk_vkGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR *pModes) DECLSPEC_HIDDEN;
 VkResult thunk_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, VkImageFormatProperties2 *pImageFormatProperties) DECLSPEC_HIDDEN;
 VkResult thunk_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, VkImageFormatProperties2 *pImageFormatProperties) DECLSPEC_HIDDEN;
 VkResult thunk_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) DECLSPEC_HIDDEN;
+VkResult thunk_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes) DECLSPEC_HIDDEN;
 
 typedef struct VkAcquireNextImageInfoKHR_host
 {
@@ -528,6 +540,13 @@ typedef struct VkMemoryRequirements2_host
     VkMemoryRequirements_host memoryRequirements;
 } VkMemoryRequirements2_host;
 
+typedef struct VkPhysicalDeviceSurfaceInfo2KHR_host
+{
+    VkStructureType sType;
+    const void *pNext;
+    VkSurfaceKHR surface;
+} VkPhysicalDeviceSurfaceInfo2KHR_host;
+
 typedef struct VkImageMemoryRequirementsInfo2_host
 {
     VkStructureType sType;
@@ -823,6 +842,7 @@ void free_VkImageMemoryBarrier_array(VkImageMemoryBarrier_host *in, uint32_t cou
 /* For use by vkDevice and children */
 struct vulkan_device_funcs
 {
+    VkResult (*p_vkAcquireFullScreenExclusiveModeEXT)(VkDevice, VkSwapchainKHR);
 #if defined(USE_STRUCT_CONVERSION)
     VkResult (*p_vkAcquireNextImage2KHR)(VkDevice, const VkAcquireNextImageInfoKHR_host *, uint32_t *);
 #else
@@ -1150,6 +1170,11 @@ struct vulkan_device_funcs
     void (*p_vkGetDeviceGroupPeerMemoryFeatures)(VkDevice, uint32_t, uint32_t, uint32_t, VkPeerMemoryFeatureFlags *);
     void (*p_vkGetDeviceGroupPeerMemoryFeaturesKHR)(VkDevice, uint32_t, uint32_t, uint32_t, VkPeerMemoryFeatureFlags *);
     VkResult (*p_vkGetDeviceGroupPresentCapabilitiesKHR)(VkDevice, VkDeviceGroupPresentCapabilitiesKHR *);
+#if defined(USE_STRUCT_CONVERSION)
+    VkResult (*p_vkGetDeviceGroupSurfacePresentModes2EXT)(VkDevice, const VkPhysicalDeviceSurfaceInfo2KHR_host *, VkDeviceGroupPresentModeFlagsKHR *);
+#else
+    VkResult (*p_vkGetDeviceGroupSurfacePresentModes2EXT)(VkDevice, const VkPhysicalDeviceSurfaceInfo2KHR *, VkDeviceGroupPresentModeFlagsKHR *);
+#endif
     VkResult (*p_vkGetDeviceGroupSurfacePresentModesKHR)(VkDevice, VkSurfaceKHR, VkDeviceGroupPresentModeFlagsKHR *);
     void (*p_vkGetDeviceMemoryCommitment)(VkDevice, VkDeviceMemory, VkDeviceSize *);
     void (*p_vkGetDeviceQueue)(VkDevice, uint32_t, uint32_t, VkQueue *);
@@ -1231,6 +1256,7 @@ struct vulkan_device_funcs
     VkResult (*p_vkQueueSetPerformanceConfigurationINTEL)(VkQueue, VkPerformanceConfigurationINTEL);
     VkResult (*p_vkQueueSubmit)(VkQueue, uint32_t, const VkSubmitInfo *, VkFence);
     VkResult (*p_vkQueueWaitIdle)(VkQueue);
+    VkResult (*p_vkReleaseFullScreenExclusiveModeEXT)(VkDevice, VkSwapchainKHR);
     VkResult (*p_vkReleasePerformanceConfigurationINTEL)(VkDevice, VkPerformanceConfigurationINTEL);
     VkResult (*p_vkResetCommandBuffer)(VkCommandBuffer, VkCommandBufferResetFlags);
     VkResult (*p_vkResetCommandPool)(VkDevice, VkCommandPool, VkCommandPoolResetFlags);
@@ -1332,13 +1358,19 @@ struct vulkan_instance_funcs
     VkResult (*p_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *, uint32_t *, VkSurfaceFormat2KHR *);
 #endif
     VkResult (*p_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkSurfaceFormatKHR *);
+#if defined(USE_STRUCT_CONVERSION)
+    VkResult (*p_vkGetPhysicalDeviceSurfacePresentModes2EXT)(VkPhysicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR_host *, uint32_t *, VkPresentModeKHR *);
+#else
+    VkResult (*p_vkGetPhysicalDeviceSurfacePresentModes2EXT)(VkPhysicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *, uint32_t *, VkPresentModeKHR *);
+#endif
     VkResult (*p_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkPresentModeKHR *);
     VkResult (*p_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice, uint32_t, VkSurfaceKHR, VkBool32 *);
     VkResult (*p_vkGetPhysicalDeviceToolPropertiesEXT)(VkPhysicalDevice, uint32_t *, VkPhysicalDeviceToolPropertiesEXT *);
     VkBool32 (*p_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice, uint32_t);
 };
 
 #define ALL_VK_DEVICE_FUNCS() \
+    USE_VK_FUNC(vkAcquireFullScreenExclusiveModeEXT) \
     USE_VK_FUNC(vkAcquireNextImage2KHR) \
     USE_VK_FUNC(vkAcquireNextImageKHR) \
     USE_VK_FUNC(vkAcquirePerformanceConfigurationINTEL) \
@@ -1511,6 +1553,7 @@ struct vulkan_instance_funcs
     USE_VK_FUNC(vkGetDeviceGroupPeerMemoryFeatures) \
     USE_VK_FUNC(vkGetDeviceGroupPeerMemoryFeaturesKHR) \
     USE_VK_FUNC(vkGetDeviceGroupPresentCapabilitiesKHR) \
+    USE_VK_FUNC(vkGetDeviceGroupSurfacePresentModes2EXT) \
     USE_VK_FUNC(vkGetDeviceGroupSurfacePresentModesKHR) \
     USE_VK_FUNC(vkGetDeviceMemoryCommitment) \
     USE_VK_FUNC(vkGetDeviceQueue) \
@@ -1548,6 +1591,7 @@ struct vulkan_instance_funcs
     USE_VK_FUNC(vkQueueSetPerformanceConfigurationINTEL) \
     USE_VK_FUNC(vkQueueSubmit) \
     USE_VK_FUNC(vkQueueWaitIdle) \
+    USE_VK_FUNC(vkReleaseFullScreenExclusiveModeEXT) \
     USE_VK_FUNC(vkReleasePerformanceConfigurationINTEL) \
     USE_VK_FUNC(vkResetCommandBuffer) \
     USE_VK_FUNC(vkResetCommandPool) \
@@ -1602,6 +1646,7 @@ struct vulkan_instance_funcs
     USE_VK_FUNC(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \
     USE_VK_FUNC(vkGetPhysicalDeviceSurfaceFormats2KHR) \
     USE_VK_FUNC(vkGetPhysicalDeviceSurfaceFormatsKHR) \
+    USE_VK_FUNC(vkGetPhysicalDeviceSurfacePresentModes2EXT) \
     USE_VK_FUNC(vkGetPhysicalDeviceSurfacePresentModesKHR) \
     USE_VK_FUNC(vkGetPhysicalDeviceSurfaceSupportKHR) \
     USE_VK_FUNC(vkGetPhysicalDeviceWin32PresentationSupportKHR)
diff --git a/include/wine/vulkan.h b/include/wine/vulkan.h
index 7bf6a0a07f8..0f8de3d21c2 100644
--- a/include/wine/vulkan.h
+++ b/include/wine/vulkan.h
@@ -348,6 +350,8 @@
 #define VK_EXT_YCBCR_IMAGE_ARRAYS_EXTENSION_NAME "VK_EXT_ycbcr_image_arrays"
 #define VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_SPEC_VERSION 1
 #define VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME "VK_KHR_uniform_buffer_standard_layout"
+#define VK_EXT_FULL_SCREEN_EXCLUSIVE_SPEC_VERSION 4
+#define VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME "VK_EXT_full_screen_exclusive"
 #define VK_EXT_HEADLESS_SURFACE_SPEC_VERSION 1
 #define VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME "VK_EXT_headless_surface"
 #define VK_EXT_LINE_RASTERIZATION_SPEC_VERSION 1
@@ -1403,6 +1407,15 @@ typedef enum VkFrontFace
     VK_FRONT_FACE_MAX_ENUM = 0x7fffffff,
 } VkFrontFace;
 
+typedef enum VkFullScreenExclusiveEXT
+{
+    VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT = 0,
+    VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT = 1,
+    VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT = 2,
+    VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT = 3,
+    VK_FULL_SCREEN_EXCLUSIVE_EXT_MAX_ENUM = 0x7fffffff,
+} VkFullScreenExclusiveEXT;
+
 typedef enum VkGeometryFlagBitsKHR
 {
     VK_GEOMETRY_OPAQUE_BIT_KHR = 0x00000001,
@@ -1909,6 +1922,7 @@ typedef enum VkResolveModeFlagBitsKHR
 
 typedef enum VkResult
 {
+    VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT = -1000255000,
     VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS = -1000257000,
     VK_ERROR_NOT_PERMITTED_EXT = -1000174001,
     VK_ERROR_FRAGMENTATION = -1000161000,
@@ -2411,6 +2428,9 @@ typedef enum VkStructureType
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT = 1000251000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT = 1000252000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES = 1000253000,
+    VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT = 1000255000,
+    VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT = 1000255001,
+    VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT = 1000255002,
     VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT = 1000256000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES = 1000257000,
     VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO = 1000257002,
@@ -4546,6 +4543,20 @@ typedef struct VkSubresourceLayout
     VkDeviceSize WINE_VK_ALIGN(8) depthPitch;
 } VkSubresourceLayout;
 
+typedef struct VkSurfaceCapabilitiesFullScreenExclusiveEXT
+{
+    VkStructureType sType;
+    void *pNext;
+    VkBool32 fullScreenExclusiveSupported;
+} VkSurfaceCapabilitiesFullScreenExclusiveEXT;
+
+typedef struct VkSurfaceFullScreenExclusiveWin32InfoEXT
+{
+    VkStructureType sType;
+    const void *pNext;
+    HMONITOR hmonitor;
+} VkSurfaceFullScreenExclusiveWin32InfoEXT;
+
 typedef struct VkSurfaceFormatKHR
 {
     VkFormat format;
@@ -5106,6 +5133,13 @@ typedef struct VkVertexInputAttributeDescription
     uint32_t offset;
 } VkVertexInputAttributeDescription;
 
+typedef struct VkSurfaceFullScreenExclusiveInfoEXT
+{
+    VkStructureType sType;
+    void *pNext;
+    VkFullScreenExclusiveEXT fullScreenExclusive;
+} VkSurfaceFullScreenExclusiveInfoEXT;
+
 typedef struct VkVertexInputBindingDivisorDescriptionEXT
 {
     uint32_t binding;
@@ -7057,6 +7119,7 @@ typedef struct VkBindSparseInfo
     const VkSemaphore *pSignalSemaphores;
 } VkBindSparseInfo;
 
+typedef VkResult (VKAPI_PTR *PFN_vkAcquireFullScreenExclusiveModeEXT)(VkDevice, VkSwapchainKHR);
 typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImage2KHR)(VkDevice, const VkAcquireNextImageInfoKHR *, uint32_t *);
 typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImageKHR)(VkDevice, VkSwapchainKHR, uint64_t, VkSemaphore, VkFence, uint32_t *);
 typedef VkResult (VKAPI_PTR *PFN_vkAcquirePerformanceConfigurationINTEL)(VkDevice, const VkPerformanceConfigurationAcquireInfoINTEL *, VkPerformanceConfigurationINTEL *);
@@ -7242,6 +7305,7 @@ typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice, const
 typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeatures)(VkDevice, uint32_t, uint32_t, uint32_t, VkPeerMemoryFeatureFlags *);
 typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)(VkDevice, uint32_t, uint32_t, uint32_t, VkPeerMemoryFeatureFlags *);
 typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHR)(VkDevice, VkDeviceGroupPresentCapabilitiesKHR *);
+typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModes2EXT)(VkDevice, const VkPhysicalDeviceSurfaceInfo2KHR *, VkDeviceGroupPresentModeFlagsKHR *);
 typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModesKHR)(VkDevice, VkSurfaceKHR, VkDeviceGroupPresentModeFlagsKHR *);
 typedef void (VKAPI_PTR *PFN_vkGetDeviceMemoryCommitment)(VkDevice, VkDeviceMemory, VkDeviceSize *);
 typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetDeviceProcAddr)(VkDevice, const char *);
@@ -7290,6 +7354,7 @@ typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkP
 typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice, VkSurfaceKHR, VkSurfaceCapabilitiesKHR *);
 typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *, uint32_t *, VkSurfaceFormat2KHR *);
 typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkSurfaceFormatKHR *);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT)(VkPhysicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *, uint32_t *, VkPresentModeKHR *);
 typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkPresentModeKHR *);
 typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice, uint32_t, VkSurfaceKHR, VkBool32 *);
 typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice, uint32_t);
@@ -7317,6 +7384,7 @@ typedef VkResult (VKAPI_PTR *PFN_vkQueuePresentKHR)(VkQueue, const VkPresentInfo
 typedef VkResult (VKAPI_PTR *PFN_vkQueueSetPerformanceConfigurationINTEL)(VkQueue, VkPerformanceConfigurationINTEL);
 typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit)(VkQueue, uint32_t, const VkSubmitInfo *, VkFence);
 typedef VkResult (VKAPI_PTR *PFN_vkQueueWaitIdle)(VkQueue);
+typedef VkResult (VKAPI_PTR *PFN_vkReleaseFullScreenExclusiveModeEXT)(VkDevice, VkSwapchainKHR);
 typedef VkResult (VKAPI_PTR *PFN_vkReleasePerformanceConfigurationINTEL)(VkDevice, VkPerformanceConfigurationINTEL);
 typedef VkResult (VKAPI_PTR *PFN_vkResetCommandBuffer)(VkCommandBuffer, VkCommandBufferResetFlags);
 typedef VkResult (VKAPI_PTR *PFN_vkResetCommandPool)(VkDevice, VkCommandPool, VkCommandPoolResetFlags);
@@ -7337,6 +7405,7 @@ typedef VkResult (VKAPI_PTR *PFN_vkWaitForFences)(VkDevice, uint32_t, const VkFe
 typedef VkResult (VKAPI_PTR *PFN_vkWaitSemaphoresKHR)(VkDevice, const VkSemaphoreWaitInfoKHR *, uint64_t);
 
 #ifndef VK_NO_PROTOTYPES
+VkResult VKAPI_CALL vkAcquireFullScreenExclusiveModeEXT(VkDevice device, VkSwapchainKHR swapchain);
 VkResult VKAPI_CALL vkAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR *pAcquireInfo, uint32_t *pImageIndex);
 VkResult VKAPI_CALL vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex);
 VkResult VKAPI_CALL vkAcquirePerformanceConfigurationINTEL(VkDevice device, const VkPerformanceConfigurationAcquireInfoINTEL *pAcquireInfo, VkPerformanceConfigurationINTEL *pConfiguration);
@@ -7522,6 +7591,7 @@ void VKAPI_CALL vkGetDescriptorSetLayoutSupportKHR(VkDevice device, const VkDesc
 void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags *pPeerMemoryFeatures);
 void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeaturesKHR(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags *pPeerMemoryFeatures);
 VkResult VKAPI_CALL vkGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR *pDeviceGroupPresentCapabilities);
+VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModes2EXT(VkDevice device, const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, VkDeviceGroupPresentModeFlagsKHR *pModes);
 VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR *pModes);
 void VKAPI_CALL vkGetDeviceMemoryCommitment(VkDevice device, VkDeviceMemory memory, VkDeviceSize *pCommittedMemoryInBytes);
 PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice device, const char *pName);
@@ -7570,6 +7640,7 @@ void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice
 VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *pSurfaceCapabilities);
 VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, uint32_t *pSurfaceFormatCount, VkSurfaceFormat2KHR *pSurfaceFormats);
 VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pSurfaceFormatCount, VkSurfaceFormatKHR *pSurfaceFormats);
+VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModes2EXT(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes);
 VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes);
 VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32 *pSupported);
 VkBool32 VKAPI_CALL vkGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex);
@@ -7597,6 +7670,7 @@ VkResult VKAPI_CALL vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPr
 VkResult VKAPI_CALL vkQueueSetPerformanceConfigurationINTEL(VkQueue queue, VkPerformanceConfigurationINTEL configuration);
 VkResult VKAPI_CALL vkQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence);
 VkResult VKAPI_CALL vkQueueWaitIdle(VkQueue queue);
+VkResult VKAPI_CALL vkReleaseFullScreenExclusiveModeEXT(VkDevice device, VkSwapchainKHR swapchain);
 VkResult VKAPI_CALL vkReleasePerformanceConfigurationINTEL(VkDevice device, VkPerformanceConfigurationINTEL configuration);
 VkResult VKAPI_CALL vkResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags);
 VkResult VKAPI_CALL vkResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags);
From 312d5ea558e2756f5893d33d8e3c90afcb44811c Mon Sep 17 00:00:00 2001
From: Andrew Eikum <coldpie@fastmail.com>
Date: Wed, 18 Mar 2020 13:26:02 -0500
Subject: [PATCH] make exts optional

---
 dlls/winevulkan/vulkan.c  | 33 +++++++++++++++++++++++++++------
 dlls/winex11.drv/vulkan.c | 15 ++++++++++++---
 2 files changed, 39 insertions(+), 9 deletions(-)

diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
index 1e730a415bc..f36315534b9 100644
--- a/dlls/winevulkan/vulkan.c
+++ b/dlls/winevulkan/vulkan.c
@@ -142,11 +142,19 @@ static struct VkPhysicalDevice_T *wine_vk_physical_device_alloc(struct VkInstanc
 
     for (i = 0; i < wine_vk_device_extension_faked_count(); i++)
     {
-        object->extensions[j] = *wine_vk_device_extension_faked_idx(i);
-        j++;
+        const VkExtensionProperties *e = wine_vk_device_extension_faked_idx(i);
+
+        if(!strcmp(e->extensionName, "VK_EXT_full_screen_exclusive") &&
+                (!vk_funcs->p_vkGetPhysicalDeviceSurfaceCapabilities2KHR ||
+                 !vk_funcs->p_vkGetPhysicalDeviceSurfaceFormats2KHR)){
+            /* ignore */
+        }else{
+            object->extensions[j] = *e;
+            j++;
+        }
     }
 
-    object->extension_count = num_properties;
+    object->extension_count = j;
 
     heap_free(host_properties);
     return object;
@@ -807,7 +815,14 @@ VkResult WINAPI wine_vkEnumerateInstanceExtensionProperties(const char *layer_na
     for (i = 0; i < num_host_properties; i++)
     {
         if (wine_vk_instance_extension_supported(host_properties[i].extensionName))
-            num_properties++;
+        {
+            if(!strcmp(host_properties[i].extensionName, "VK_KHR_get_physical_device_properties2") &&
+                    (!vk_funcs->p_vkGetPhysicalDeviceSurfaceCapabilities2KHR ||
+                     !vk_funcs->p_vkGetPhysicalDeviceSurfaceFormats2KHR)){
+                /* ignore - outdated vulkan loader */
+            }else
+                num_properties++;
+        }
         else
             TRACE("Instance extension '%s' is not supported.\n", host_properties[i].extensionName);
     }
@@ -824,8 +839,14 @@ VkResult WINAPI wine_vkEnumerateInstanceExtensionProperties(const char *layer_na
     {
         if (wine_vk_instance_extension_supported(host_properties[i].extensionName))
         {
-            TRACE("Enabling extension '%s'.\n", host_properties[i].extensionName);
-            properties[j++] = host_properties[i];
+            if(!strcmp(host_properties[i].extensionName, "VK_KHR_get_physical_device_properties2") &&
+                    (!vk_funcs->p_vkGetPhysicalDeviceSurfaceCapabilities2KHR ||
+                     !vk_funcs->p_vkGetPhysicalDeviceSurfaceFormats2KHR)){
+                /* ignore - outdated vulkan loader */
+            }else{
+                TRACE("Enabling extension '%s'.\n", host_properties[i].extensionName);
+                properties[j++] = host_properties[i];
+            }
         }
     }
     *count = min(*count, num_properties);
diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c
index 9bb33339af5..8f08ac19a2a 100644
--- a/dlls/winex11.drv/vulkan.c
+++ b/dlls/winex11.drv/vulkan.c
@@ -56,6 +56,8 @@ static CRITICAL_SECTION context_section = { &critsect_debug, -1, 0, 0, 0, 0 };
 
 static XContext vulkan_hwnd_context;
 
+static struct vulkan_funcs vulkan_funcs;
+
 #define VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR 1000004000
 
 struct wine_vk_surface
@@ -135,6 +137,13 @@ static BOOL WINAPI wine_vk_init(INIT_ONCE *once, void *param, void **context)
     LOAD_FUNCPTR(vkQueuePresentKHR);
     LOAD_OPTIONAL_FUNCPTR(vkGetDeviceGroupSurfacePresentModesKHR);
     LOAD_OPTIONAL_FUNCPTR(vkGetPhysicalDevicePresentRectanglesKHR);
+
+    if(!pvkGetPhysicalDeviceSurfaceCapabilities2KHR){
+        vulkan_funcs.p_vkGetPhysicalDeviceSurfaceCapabilities2KHR = NULL;
+    }
+    if(!pvkGetPhysicalDeviceSurfaceFormats2KHR){
+        vulkan_funcs.p_vkGetPhysicalDeviceSurfaceFormats2KHR = NULL;
+    }
 #undef LOAD_FUNCPTR
 #undef LOAD_OPTIONAL_FUNCPTR
 
@@ -612,7 +621,7 @@ static VkBool32 X11DRV_query_fs_hack(VkExtent2D *real_sz, VkExtent2D *user_sz,
     return VK_FALSE;
 }
 
-static const struct vulkan_funcs vulkan_funcs =
+static struct vulkan_funcs vulkan_funcs =
 {
     X11DRV_vkCreateInstance,
     X11DRV_vkCreateSwapchainKHR,
From 9c92a32fdd5c71e82e30fa3a85fd9f0c018915d3 Mon Sep 17 00:00:00 2001
From: Joshua Ashton <joshua@froggi.es>
Date: Tue, 24 Mar 2020 02:53:52 +0000
Subject: [PATCH] winevulkan: Nuke unsupported pNexts from vkCreateSwapchainKHR

Fixes RenderDoccing DXVK, and potential issues down the line in games using the fullscreen and other exts
---
 dlls/winevulkan/vulkan.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
index f36315534b9..fdce58c9500 100644
--- a/dlls/winevulkan/vulkan.c
+++ b/dlls/winevulkan/vulkan.c
@@ -49,6 +49,15 @@ static void *wine_vk_find_struct_(void *s, VkStructureType t)
     return NULL;
 }
 
+#define wine_vk_exchange_pnext(a, b) wine_vk_exchange_pnext_((VkBaseOutStructure *)a, (VkBaseOutStructure *)b)
+static void wine_vk_exchange_pnext_(VkBaseOutStructure *a, VkBaseOutStructure *b)
+{
+    b->pNext = a->pNext;
+    a->pNext = b;
+}
+
+#define wine_vk_copy_pnext(a, ctype, stype, b) do { ctype* lookup = wine_vk_find_struct(a, stype); if (lookup) { b = *lookup; wine_vk_exchange_pnext(a, &b); } } while (0)
+
 static void *wine_vk_get_global_proc_addr(const char *name);
 
 static const struct vulkan_funcs *vk_funcs;
@@ -1739,6 +1748,9 @@ VkResult WINAPI wine_vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCrea
 #else
     VkSwapchainCreateInfoKHR our_createinfo;
 #endif
+    VkDeviceGroupSwapchainCreateInfoKHR  our_device_group_swapchain_create_info;
+    VkImageFormatListCreateInfo       our_image_format_list_create_info;
+
     VkExtent2D user_sz;
     struct VkSwapchainKHR_T *object;
     uint32_t i;
@@ -1754,6 +1766,19 @@ VkResult WINAPI wine_vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCrea
 
     convert_VkSwapchainCreateInfoKHR_win_to_host(pCreateInfo, &our_createinfo);
 
+    our_createinfo.pNext = NULL;
+
+    wine_vk_copy_pnext(&our_createinfo, VkDeviceGroupSwapchainCreateInfoKHR, DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR, our_device_group_swapchain_create_info);
+
+    wine_vk_copy_pnext(&our_createinfo, VkImageFormatListCreateInfo, IMAGE_FORMAT_LIST_CREATE_INFO, our_image_format_list_create_info);
+
+    // VkSwapchainCounterCreateInfoEXT is not in our version of WineVulkan
+    // Come back to me when this gets into Proton Wine!
+
+    // Ignoring VkSurfaceFullScreenExclusiveInfoEXT and VkSurfaceFullScreenExclusiveWin32InfoEXT
+    // as we want to nuke those
+    // and VkSwapchainDisplayNativeHdrCreateInfoAMD (blacklisted for HDR for now)
+
     if(our_createinfo.oldSwapchain)
         our_createinfo.oldSwapchain = ((struct VkSwapchainKHR_T *)(UINT_PTR)our_createinfo.oldSwapchain)->swapchain;
 
